PixelBox GL3PlusHardwarePixelBuffer::lockImpl( const Image::Box &lockBox, LockOptions options ) { //Allocate memory for the entire image, as the buffer //maynot be freed and be reused in subsequent calls. allocateBuffer( PixelUtil::getMemorySize( mWidth, mHeight, mDepth, mFormat ) ); mBuffer = PixelBox( lockBox.getWidth(), lockBox.getHeight(), lockBox.getDepth(), mFormat, mBuffer.data ); mCurrentLock = mBuffer; mCurrentLock.left = lockBox.left; mCurrentLock.right += lockBox.left; mCurrentLock.top = lockBox.top; mCurrentLock.bottom += lockBox.top; if(options != HardwareBuffer::HBL_DISCARD) { // Download the old contents of the texture download( mCurrentLock ); } mCurrentLockOptions = options; mLockedBox = lockBox; mCurrentLock = mBuffer; return mBuffer; }
void GLES2HardwarePixelBuffer::blitFromMemory(const PixelBox &src, const Image::Box &dstBox) { if (!mBuffer.contains(dstBox)) { OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Destination box out of range", "GLES2HardwarePixelBuffer::blitFromMemory"); } PixelBox scaled; if (src.getWidth() != dstBox.getWidth() || src.getHeight() != dstBox.getHeight() || src.getDepth() != dstBox.getDepth()) { // Scale to destination size. // This also does pixel format conversion if needed allocateBuffer(); scaled = mBuffer.getSubVolume(dstBox); Image::scale(src, scaled, Image::FILTER_BILINEAR); } #if OGRE_PLATFORM != OGRE_PLATFORM_APPLE_IOS else if ((src.format != mFormat) || ((GLES2PixelUtil::getGLOriginFormat(src.format) == 0) && (src.format != PF_R8G8B8))) #else else if (GLES2PixelUtil::getGLOriginFormat(src.format) == 0) #endif { // Extents match, but format is not accepted as valid source format for GL // do conversion in temporary buffer allocateBuffer(); scaled = mBuffer.getSubVolume(dstBox); PixelUtil::bulkPixelConversion(src, scaled); } else { allocateBuffer(); // No scaling or conversion needed scaled = src; if (src.format == PF_R8G8B8) { scaled.format = PF_B8G8R8; PixelUtil::bulkPixelConversion(src, scaled); } #if OGRE_PLATFORM == OGRE_PLATFORM_NACL if (src.format == PF_A8R8G8B8) { scaled.format = PF_A8B8G8R8; PixelUtil::bulkPixelConversion(src, scaled); } #endif } upload(scaled, dstBox); freeBuffer(); }
//----------------------------------------------------------------------------- void D3D11HardwarePixelBuffer::blitToMemory(const Image::Box &srcBox, const PixelBox &dst) { // Decide on pixel format of temp surface PixelFormat tmpFormat = mFormat; if(D3D11Mappings::_getPF(dst.format) != DXGI_FORMAT_UNKNOWN) { tmpFormat = dst.format; } assert(srcBox.getDepth() == 1 && dst.getDepth() == 1); //This is a pointer to the texture we're trying to copy //Only implemented for 2D at the moment... ID3D11Texture2D *textureResource = mParentTexture->GetTex2D(); // get the description of the texture D3D11_TEXTURE2D_DESC desc = {0}; textureResource->GetDesc( &desc ); //Alter the description to set up a staging texture desc.Usage = D3D11_USAGE_STAGING; //This texture is not bound to any part of the pipeline desc.BindFlags = 0; //Allow CPU Access desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; //No Misc Flags desc.MiscFlags = 0; //Create the staging texture ID3D11Texture2D* pStagingTexture = NULL; mDevice->CreateTexture2D( &desc, NULL, &pStagingTexture ); //Copy our texture into the staging texture mDevice.GetImmediateContext()->CopyResource( pStagingTexture, textureResource ); //Create a mapped resource and map the staging texture to the resource D3D11_MAPPED_SUBRESOURCE mapped = {0}; mDevice.GetImmediateContext()->Map( pStagingTexture, 0, D3D11_MAP_READ , 0, &mapped ); // read the data out of the texture. unsigned int rPitch = mapped.RowPitch; BYTE *data = ((BYTE *)mapped.pData); //Using existing OGRE functions DXGI_MAPPED_RECT lrect; lrect.pBits = data; lrect.Pitch = rPitch; PixelBox locked(dst.getWidth(), dst.getHeight(), dst.getDepth(), tmpFormat); fromD3DLock(locked, lrect); PixelUtil::bulkPixelConversion(locked, dst); //Release the staging texture mDevice.GetImmediateContext()->Unmap( pStagingTexture, 0 ); pStagingTexture->Release(); }
void GLESHardwarePixelBuffer::blitToMemory(const Image::Box &srcBox, const PixelBox &dst) { if (!mBuffer.contains(srcBox)) { OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "source box out of range", "GLESHardwarePixelBuffer::blitToMemory"); } if (srcBox.left == 0 && srcBox.right == getWidth() && srcBox.top == 0 && srcBox.bottom == getHeight() && srcBox.front == 0 && srcBox.back == getDepth() && dst.getWidth() == getWidth() && dst.getHeight() == getHeight() && dst.getDepth() == getDepth() && GLESPixelUtil::getGLOriginFormat(dst.format) != 0) { // The direct case: the user wants the entire texture in a format supported by GL // so we don't need an intermediate buffer download(dst); } else { // Use buffer for intermediate copy allocateBuffer(); // Download entire buffer download(mBuffer); if(srcBox.getWidth() != dst.getWidth() || srcBox.getHeight() != dst.getHeight() || srcBox.getDepth() != dst.getDepth()) { // We need scaling Image::scale(mBuffer.getSubVolume(srcBox), dst, Image::FILTER_BILINEAR); } else { // Just copy the bit that we need PixelUtil::bulkPixelConversion(mBuffer.getSubVolume(srcBox), dst); } freeBuffer(); } }
void GL3PlusHardwarePixelBuffer::blitFromMemory(const PixelBox &src, const Image::Box &dstBox) { if (!mBuffer.contains(dstBox)) { OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Destination box out of range", "GL3PlusHardwarePixelBuffer::blitFromMemory"); } PixelBox scaled; if (src.getWidth() != dstBox.getWidth() || src.getHeight() != dstBox.getHeight() || src.getDepth() != dstBox.getDepth()) { // Scale to destination size. // This also does pixel format conversion if needed. allocateBuffer( mSizeInBytes ); scaled = mBuffer.getSubVolume(dstBox); Image::scale(src, scaled, Image::FILTER_BILINEAR); } else if (GL3PlusPixelUtil::getGLOriginFormat(src.format) == 0) { // Extents match, but format is not accepted as valid // source format for GL. Do conversion in temporary buffer. allocateBuffer( mSizeInBytes ); scaled = mBuffer.getSubVolume(dstBox); PixelUtil::bulkPixelConversion(src, scaled); } else { allocateBuffer( mSizeInBytes ); // No scaling or conversion needed. scaled = src; } upload(scaled, dstBox); freeBuffer(); }
//----------------------------------------------------------------------------- // blitFromMemory doing hardware trilinear scaling void GLESTextureBuffer::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 if(!GL_OES_framebuffer_object || PixelUtil::isLuminance(src_orig.format) || PixelUtil::isLuminance(mFormat) || (src_orig.getWidth() == dstBox.getWidth() && src_orig.getHeight() == dstBox.getHeight() && src_orig.getDepth() == dstBox.getDepth())) { GLESHardwarePixelBuffer::blitFromMemory(src_orig, dstBox); return; } if(!mBuffer.contains(dstBox)) OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Destination box out of range", "GLESTextureBuffer::blitFromMemory"); // For scoped deletion of conversion buffer MemoryDataStreamPtr buf; PixelBox src; // First, convert the srcbox to a OpenGL compatible pixel format if(GLESPixelUtil::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 = GL_TEXTURE_2D; GLsizei width = GLESPixelUtil::optionalPO2(src.getWidth()); GLsizei height = GLESPixelUtil::optionalPO2(src.getHeight()); GLenum format = GLESPixelUtil::getClosestGLInternalFormat(src.format); GLenum datatype = GLESPixelUtil::getGLOriginDataType(src.format); // Generate texture name glGenTextures(1, &id); GL_CHECK_ERROR; // Set texture type glBindTexture(target, id); GL_CHECK_ERROR; // Set automatic mipmap generation; nice for minimisation glTexParameteri(target, GL_GENERATE_MIPMAP, GL_TRUE ); GL_CHECK_ERROR; // Allocate texture memory glTexImage2D(target, 0, format, width, height, 0, format, datatype, 0); GL_CHECK_ERROR; // GL texture buffer GLESTextureBuffer tex(BLANKSTRING, 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 glDeleteTextures(1, &id); GL_CHECK_ERROR; }
//----------------------------------------------------------------------------- // Very fast texture-to-texture blitter and hardware bi/trilinear scaling implementation using FBO // Destination texture must be 2D // Source texture must be 2D // 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 GLESTextureBuffer::blitFromTexture(GLESTextureBuffer *src, const Image::Box &srcBox, const Image::Box &dstBox) { if(Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(RSC_FBO) == false) { // the following code depends on FBO support, it crashes if FBO is not supported. // TODO - write PBUFFER version of this function or a version that doesn't require FBO return; // for now - do nothing. } // std::cerr << "GLESTextureBuffer::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 GLESFBOManager *fboMan = static_cast<GLESFBOManager *>(GLESRTTManager::getSingletonPtr()); // Save and clear GL state for rendering glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); RenderSystem* rsys = Root::getSingleton().getRenderSystem(); rsys->_disableTextureUnitsFrom(0); // Disable alpha, depth and scissor testing, disable blending, // disable culling, disble lighting, disable fog and reset foreground // colour. glDisable(GL_ALPHA_TEST); glDisable(GL_DEPTH_TEST); glDisable(GL_SCISSOR_TEST); glDisable(GL_BLEND); glDisable(GL_CULL_FACE); glDisable(GL_LIGHTING); glDisable(GL_FOG); glColor4f(1.0f, 1.0f, 1.0f, 1.0f); GL_CHECK_ERROR; // Save and reset matrices glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_TEXTURE); glPushMatrix(); glLoadIdentity(); GL_CHECK_ERROR; // Set up source texture glBindTexture(src->mTarget, src->mTextureID); GL_CHECK_ERROR; // 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) glTexParameteri(src->mTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); GL_CHECK_ERROR; glTexParameteri(src->mTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); GL_CHECK_ERROR; } 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 imporoved quality for minimisation. glTexParameteri(src->mTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); GL_CHECK_ERROR; glTexParameteri(src->mTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); GL_CHECK_ERROR; } else { // Manual mipmaps, stay safe with bilinear filtering so that no // intermipmap leakage occurs. glTexParameteri(src->mTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); GL_CHECK_ERROR; glTexParameteri(src->mTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); GL_CHECK_ERROR; } } // Clamp to edge (fastest) glTexParameteri(src->mTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); GL_CHECK_ERROR; glTexParameteri(src->mTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); GL_CHECK_ERROR; // Store old binding so it can be restored later GLint oldfb; glGetIntegerv(GL_FRAMEBUFFER_BINDING_OES, &oldfb); GL_CHECK_ERROR; // Set up temporary FBO glBindFramebufferOES(GL_FRAMEBUFFER_OES, fboMan->getTemporaryFBO()); GL_CHECK_ERROR; GLuint tempTex = 0; if(!fboMan->checkFormat(mFormat)) { // If target format not directly supported, create intermediate texture GLenum tempFormat = GLESPixelUtil::getClosestGLInternalFormat(fboMan->getSupportedAlternative(mFormat)); glGenTextures(1, &tempTex); GL_CHECK_ERROR; glBindTexture(GL_TEXTURE_2D, tempTex); GL_CHECK_ERROR; // Allocate temporary texture of the size of the destination area glTexImage2D(GL_TEXTURE_2D, 0, tempFormat, GLESPixelUtil::optionalPO2(dstBox.getWidth()), GLESPixelUtil::optionalPO2(dstBox.getHeight()), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); GL_CHECK_ERROR; glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, tempTex, 0); GL_CHECK_ERROR; // Set viewport to size of destination slice glViewport(0, 0, dstBox.getWidth(), dstBox.getHeight()); GL_CHECK_ERROR; } else { // We are going to bind directly, so set viewport to size and position of destination slice glViewport(dstBox.left, dstBox.top, dstBox.getWidth(), dstBox.getHeight()); GL_CHECK_ERROR; } // Process each destination slice for(size_t slice=dstBox.front; slice<dstBox.back; ++slice) { if(!tempTex) { /// Bind directly bindToFramebuffer(GL_COLOR_ATTACHMENT0_OES, slice); } if(tempTex) { // Copy temporary texture glBindTexture(mTarget, mTextureID); GL_CHECK_ERROR; switch(mTarget) { case GL_TEXTURE_2D: #if OGRE_PLATFORM == OGRE_PLATFORM_ANDROID case GL_TEXTURE_CUBE_MAP_OES: #endif glCopyTexSubImage2D(mFaceTarget, mLevel, dstBox.left, dstBox.top, 0, 0, dstBox.getWidth(), dstBox.getHeight()); GL_CHECK_ERROR; break; } } } // Finish up if(!tempTex) { // Generate mipmaps if(mUsage & TU_AUTOMIPMAP) { glBindTexture(mTarget, mTextureID); GL_CHECK_ERROR; glGenerateMipmapOES(mTarget); GL_CHECK_ERROR; } } // Reset source texture to sane state glBindTexture(src->mTarget, src->mTextureID); GL_CHECK_ERROR; // Detach texture from temporary framebuffer glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, 0); GL_CHECK_ERROR; // Restore old framebuffer glBindFramebufferOES(GL_FRAMEBUFFER_OES, oldfb); GL_CHECK_ERROR; // Restore matrix stacks and render state glMatrixMode(GL_TEXTURE); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); GL_CHECK_ERROR; glDeleteTextures(1, &tempTex); GL_CHECK_ERROR; }
//----------------------------------------------------------------------------- PixelBox D3D10HardwarePixelBuffer::lockImpl(const Image::Box lockBox, LockOptions options) { // Check for misuse if(mUsage & TU_RENDERTARGET) OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "DirectX does not allow locking of or directly writing to RenderTargets. Use blitFromMemory if you need the contents.", "D3D10HardwarePixelBuffer::lockImpl"); // Set extents and format // Note that we do not carry over the left/top/front here, since the returned // PixelBox will be re-based from the locking point onwards PixelBox rval(lockBox.getWidth(), lockBox.getHeight(), lockBox.getDepth(), mFormat); // Set locking flags according to options D3D10_MAP flags = D3D10_MAP_WRITE_DISCARD ; switch(options) { case HBL_DISCARD: // D3D only likes D3DLOCK_DISCARD if you created the texture with D3DUSAGE_DYNAMIC // debug runtime flags this up, could cause problems on some drivers if (mUsage & HBU_DYNAMIC) flags = D3D10_MAP_WRITE_DISCARD; break; case HBL_READ_ONLY: flags = D3D10_MAP_READ; break; default: break; }; mDevice.clearStoredErrorMessages(); // TODO - check return values here switch(mParentTexture->getTextureType()) { case TEX_TYPE_1D: { mParentTexture->GetTex1D()->Map(static_cast<UINT>(mSubresourceIndex), flags, 0, &rval.data); if (mDevice.isError()) { String errorDescription = mDevice.getErrorDescription(); OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "D3D10 device cannot map 1D texture\nError Description:" + errorDescription, "D3D10HardwarePixelBuffer::lockImpl"); } } break; case TEX_TYPE_CUBE_MAP: case TEX_TYPE_2D: { D3D10_MAPPED_TEXTURE2D mappedTex2D; mParentTexture->GetTex2D()->Map(static_cast<UINT>(mSubresourceIndex), flags, 0, &mappedTex2D); rval.data = mappedTex2D.pData; if (mDevice.isError()) { String errorDescription = mDevice.getErrorDescription(); OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "D3D10 device cannot map 1D texture\nError Description:" + errorDescription, "D3D10HardwarePixelBuffer::lockImpl"); } } break; case TEX_TYPE_3D: { D3D10_MAPPED_TEXTURE3D mappedTex3D; mParentTexture->GetTex3D()->Map(static_cast<UINT>(mSubresourceIndex), flags, 0, &mappedTex3D); rval.data = mappedTex3D.pData; if (mDevice.isError()) { String errorDescription = mDevice.getErrorDescription(); OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "D3D10 device cannot map 1D texture\nError Description:" + errorDescription, "D3D10HardwarePixelBuffer::lockImpl"); } } break; } return rval; }
void D3D10HardwarePixelBuffer::blit(const HardwarePixelBufferSharedPtr &rsrc, const Image::Box &srcBox, const Image::Box &dstBox) { if ( (srcBox.getWidth() != dstBox.getWidth()) || (srcBox.getHeight() != dstBox.getHeight()) || (srcBox.getDepth() != dstBox.getDepth()) ) { OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "D3D10 device cannot copy a subresource - source and dest size are not the same and they have to be the same in DX10.", "D3D10HardwarePixelBuffer::blit"); } D3D10_BOX srcBoxDx10 = OgreImageBoxToDx10Box(srcBox); D3D10HardwarePixelBuffer * rsrcDx10 = static_cast<D3D10HardwarePixelBuffer *>(rsrc.get()); switch(mParentTexture->getTextureType()) { case TEX_TYPE_1D: { mDevice->CopySubresourceRegion( mParentTexture->GetTex1D(), static_cast<UINT>(mSubresourceIndex), static_cast<UINT>(dstBox.left), 0, 0, rsrcDx10->mParentTexture->GetTex1D(), static_cast<UINT>(rsrcDx10->mSubresourceIndex), &srcBoxDx10); if (mDevice.isError()) { String errorDescription = mDevice.getErrorDescription(); OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "D3D10 device cannot copy 1d subresource Region\nError Description:" + errorDescription, "D3D10HardwarePixelBuffer::blit"); } } break; case TEX_TYPE_CUBE_MAP: case TEX_TYPE_2D: { mDevice->CopySubresourceRegion( mParentTexture->GetTex2D(), static_cast<UINT>(mSubresourceIndex), static_cast<UINT>(dstBox.left), static_cast<UINT>(dstBox.top), mFace, rsrcDx10->mParentTexture->GetTex2D(), static_cast<UINT>(rsrcDx10->mSubresourceIndex), &srcBoxDx10); if (mDevice.isError()) { String errorDescription = mDevice.getErrorDescription(); OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "D3D10 device cannot copy 2d subresource Region\nError Description:" + errorDescription, "D3D10HardwarePixelBuffer::blit"); } } break; case TEX_TYPE_3D: { mDevice->CopySubresourceRegion( mParentTexture->GetTex2D(), static_cast<UINT>(mSubresourceIndex), static_cast<UINT>(dstBox.left), static_cast<UINT>(dstBox.top), static_cast<UINT>(dstBox.front), rsrcDx10->mParentTexture->GetTex2D(), static_cast<UINT>(rsrcDx10->mSubresourceIndex), &srcBoxDx10); if (mDevice.isError()) { String errorDescription = mDevice.getErrorDescription(); OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "D3D10 device cannot copy 3d subresource Region\nError Description:" + errorDescription, "D3D10HardwarePixelBuffer::blit"); } } break; } _genMipmaps(); }
//----------------------------------------------------------------------------- // 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 glBindTexture(src->mTarget, src->mTextureID); GL_CHECK_ERROR; // 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) glTexParameteri(src->mTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); GL_CHECK_ERROR; glTexParameteri(src->mTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); GL_CHECK_ERROR; } 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. glTexParameteri(src->mTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); GL_CHECK_ERROR; glTexParameteri(src->mTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); GL_CHECK_ERROR; } else { // Manual mipmaps, stay safe with bilinear filtering so that no // intermipmap leakage occurs. glTexParameteri(src->mTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); GL_CHECK_ERROR; glTexParameteri(src->mTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); GL_CHECK_ERROR; } } // Clamp to edge (fastest) glTexParameteri(src->mTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); GL_CHECK_ERROR; glTexParameteri(src->mTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); GL_CHECK_ERROR; // Store old binding so it can be restored later GLint oldfb; glGetIntegerv(GL_FRAMEBUFFER_BINDING, &oldfb); GL_CHECK_ERROR; // Set up temporary FBO glBindFramebuffer(GL_FRAMEBUFFER, fboMan->getTemporaryFBO()); GL_CHECK_ERROR; GLuint tempTex = 0; if(!fboMan->checkFormat(mFormat)) { // If target format not directly supported, create intermediate texture GLenum tempFormat = GLES2PixelUtil::getClosestGLInternalFormat(fboMan->getSupportedAlternative(mFormat)); glGenTextures(1, &tempTex); GL_CHECK_ERROR; glBindTexture(GL_TEXTURE_2D, tempTex); GL_CHECK_ERROR; #if GL_APPLE_texture_max_level glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL_APPLE, 0); GL_CHECK_ERROR; #endif // Allocate temporary texture of the size of the destination area glTexImage2D(GL_TEXTURE_2D, 0, tempFormat, GLES2PixelUtil::optionalPO2(dstBox.getWidth()), GLES2PixelUtil::optionalPO2(dstBox.getHeight()), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); GL_CHECK_ERROR; glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tempTex, 0); GL_CHECK_ERROR; // Set viewport to size of destination slice glViewport(0, 0, dstBox.getWidth(), dstBox.getHeight()); GL_CHECK_ERROR; } else { // We are going to bind directly, so set viewport to size and position of destination slice glViewport(dstBox.left, dstBox.top, dstBox.getWidth(), dstBox.getHeight()); GL_CHECK_ERROR; } // 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 glBindTexture(src->mTarget, src->mTextureID); GL_CHECK_ERROR; glEnable(src->mTarget); GL_CHECK_ERROR; 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 glVertexAttribPointer(posAttrIndex, 2, GL_FLOAT, 0, 0, squareVertices); GL_CHECK_ERROR; glEnableVertexAttribArray(posAttrIndex); GL_CHECK_ERROR; glVertexAttribPointer(texAttrIndex, 3, GL_FLOAT, 0, 0, texCoords); GL_CHECK_ERROR; glEnableVertexAttribArray(texAttrIndex); GL_CHECK_ERROR; glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); GL_CHECK_ERROR; glDisable(src->mTarget); GL_CHECK_ERROR; if(tempTex) { // Copy temporary texture glBindTexture(mTarget, mTextureID); GL_CHECK_ERROR; switch(mTarget) { case GL_TEXTURE_2D: case GL_TEXTURE_CUBE_MAP: glCopyTexSubImage2D(mFaceTarget, mLevel, dstBox.left, dstBox.top, 0, 0, dstBox.getWidth(), dstBox.getHeight()); GL_CHECK_ERROR; break; } } } // Finish up if(!tempTex) { // Generate mipmaps if(mUsage & TU_AUTOMIPMAP) { glBindTexture(mTarget, mTextureID); GL_CHECK_ERROR; glGenerateMipmap(mTarget); GL_CHECK_ERROR; } } // Reset source texture to sane state glBindTexture(src->mTarget, src->mTextureID); GL_CHECK_ERROR; // Detach texture from temporary framebuffer glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, 0); GL_CHECK_ERROR; // Restore old framebuffer glBindFramebuffer(GL_FRAMEBUFFER, oldfb); GL_CHECK_ERROR; glDeleteTextures(1, &tempTex); GL_CHECK_ERROR; }
//----------------------------------------------------------------------------- PixelBox D3D11HardwarePixelBuffer::lockImpl(const Image::Box lockBox, LockOptions options) { // Check for misuse if(mUsage & TU_RENDERTARGET) OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "DirectX does not allow locking of or directly writing to RenderTargets. Use blitFromMemory if you need the contents.", "D3D11HardwarePixelBuffer::lockImpl"); mLockBox = lockBox; // Set extents and format // Note that we do not carry over the left/top/front here, since the returned // PixelBox will be re-based from the locking point onwards PixelBox rval(lockBox.getWidth(), lockBox.getHeight(), lockBox.getDepth(), mFormat); // Set locking flags according to options D3D11_MAP flags = D3D11_MAP_WRITE_DISCARD ; switch(options) { case HBL_NO_OVERWRITE: flags = D3D11_MAP_WRITE_NO_OVERWRITE; break; case HBL_NORMAL: flags = D3D11_MAP_READ_WRITE; break; case HBL_DISCARD: flags = D3D11_MAP_WRITE_DISCARD; break; case HBL_READ_ONLY: flags = D3D11_MAP_READ; break; case HBL_WRITE_ONLY: flags = D3D11_MAP_WRITE; break; default: break; }; size_t offset = 0; if(mUsage == HBU_STATIC || mUsage & HBU_DYNAMIC) { if(mUsage == HBU_STATIC || options == HBL_READ_ONLY || options == HBL_NORMAL || options == HBL_WRITE_ONLY) rval.data = _mapstagingbuffer(flags); else _map(mParentTexture->getTextureResource(), flags, rval); // calculate the offset in bytes offset = D3D11Mappings::_getSizeInBytes(rval.format, rval.left, rval.front); // add the offset, so the right memory will be changed //rval.data = static_cast<int*>(rval.data) + offset; } else { size_t sizeOfImage = rval.getConsecutiveSize(); mDataForStaticUsageLock = new int8[sizeOfImage]; rval.data = mDataForStaticUsageLock; } // save without offset mCurrentLock = rval; mCurrentLockOptions = options; // add the offset, so the right memory will be changed rval.data = static_cast<int*>(rval.data) + offset; return rval; }
//----------------------------------------------------------------------------- // 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)); }