void GLTextureBuffer::blitFromTexture(GLTextureBuffer* src, const PixelVolume& srcBox, const PixelVolume& dstBox) { if (src->mMultisampleCount > 0 && mMultisampleCount == 0) // Resolving MS texture { if (mTarget != GL_TEXTURE_2D || mTarget != GL_TEXTURE_2D_MULTISAMPLE) BS_EXCEPT(InvalidParametersException, "Non-2D multisampled texture not supported."); GLint currentFBO = 0; glGetIntegerv(GL_FRAMEBUFFER_BINDING, ¤tFBO); GLuint readFBO = GLRTTManager::instance().getBlitReadFBO(); GLuint drawFBO = GLRTTManager::instance().getBlitDrawFBO(); // Attach source texture glBindFramebuffer(GL_FRAMEBUFFER, readFBO); src->bindToFramebuffer(0, 0, true); // Attach destination texture glBindFramebuffer(GL_FRAMEBUFFER, drawFBO); bindToFramebuffer(0, 0, true); // Perform blit glBindFramebuffer(GL_READ_FRAMEBUFFER, readFBO); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, drawFBO); glReadBuffer(GL_COLOR_ATTACHMENT0); glDrawBuffer(GL_COLOR_ATTACHMENT0); glBlitFramebuffer(srcBox.left, srcBox.top, srcBox.right, srcBox.bottom, dstBox.left, dstBox.top, dstBox.right, dstBox.bottom, GL_COLOR_BUFFER_BIT, GL_NEAREST); // Restore the previously bound FBO glBindFramebuffer(GL_FRAMEBUFFER, currentFBO); } else // Just plain copy { if (mMultisampleCount != src->mMultisampleCount) BS_EXCEPT(InvalidParametersException, "When copying textures their multisample counts must match."); if (mTarget == GL_TEXTURE_3D) // 3D textures can't have arrays so their Z coordinate is handled differently { glCopyImageSubData(src->mTextureID, src->mTarget, src->mLevel, srcBox.left, srcBox.top, srcBox.front, mTextureID, mTarget, mLevel, dstBox.left, dstBox.top, dstBox.front, srcBox.getWidth(), srcBox.getHeight(), srcBox.getDepth()); } else { glCopyImageSubData(src->mTextureID, src->mTarget, src->mLevel, srcBox.left, srcBox.top, src->mFace, mTextureID, mTarget, mLevel, dstBox.left, dstBox.top, mFace, srcBox.getWidth(), srcBox.getHeight(), 1); } } }
void GLTextureBuffer::upload(const PixelData &data, const PixelVolume &dest) { if((mUsage & TU_RENDERTARGET) != 0) BS_EXCEPT(NotImplementedException, "Writing to render texture from CPU not supported."); if ((mUsage & TU_DEPTHSTENCIL) != 0) BS_EXCEPT(NotImplementedException, "Writing to depth stencil texture from CPU not supported."); glBindTexture( mTarget, mTextureID ); if(PixelUtil::isCompressed(data.getFormat())) { if(data.getFormat() != mFormat || !data.isConsecutive()) BS_EXCEPT(InvalidParametersException, "Compressed images must be consecutive, in the source format"); GLenum format = GLPixelUtil::getClosestGLInternalFormat(mFormat); switch(mTarget) { case GL_TEXTURE_1D: if (dest.left == 0) { glCompressedTexImage1D(GL_TEXTURE_1D, mLevel, format, dest.getWidth(), 0, data.getConsecutiveSize(), data.getData()); } else { glCompressedTexSubImage1D(GL_TEXTURE_1D, mLevel, dest.left, dest.getWidth(), format, data.getConsecutiveSize(), data.getData()); } break; case GL_TEXTURE_2D: case GL_TEXTURE_CUBE_MAP: if (dest.left == 0 && dest.top == 0) { glCompressedTexImage2D(mFaceTarget, mLevel, format, dest.getWidth(), dest.getHeight(), 0, data.getConsecutiveSize(), data.getData()); } else { glCompressedTexSubImage2D(mFaceTarget, mLevel, dest.left, dest.top, dest.getWidth(), dest.getHeight(), format, data.getConsecutiveSize(), data.getData()); } break; case GL_TEXTURE_3D: if (dest.left == 0 && dest.top == 0 && dest.front == 0) { glCompressedTexImage3D(GL_TEXTURE_3D, mLevel, format, dest.getWidth(), dest.getHeight(), dest.getDepth(), 0, data.getConsecutiveSize(), data.getData()); } else { glCompressedTexSubImage3D(GL_TEXTURE_3D, mLevel, dest.left, dest.top, dest.front, dest.getWidth(), dest.getHeight(), dest.getDepth(), format, data.getConsecutiveSize(), data.getData()); } break; } } else { if(data.getWidth() != data.getRowPitch()) glPixelStorei(GL_UNPACK_ROW_LENGTH, data.getRowPitch()); if(data.getHeight()*data.getWidth() != data.getSlicePitch()) glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, (data.getSlicePitch()/data.getWidth())); if(data.getLeft() > 0 || data.getTop() > 0 || data.getFront() > 0) glPixelStorei(GL_UNPACK_SKIP_PIXELS, data.getLeft() + data.getRowPitch() * data.getTop() + data.getSlicePitch() * data.getFront()); if((data.getWidth()*PixelUtil::getNumElemBytes(data.getFormat())) & 3) glPixelStorei(GL_UNPACK_ALIGNMENT, 1); switch(mTarget) { case GL_TEXTURE_1D: glTexSubImage1D(GL_TEXTURE_1D, mLevel, dest.left, dest.getWidth(), GLPixelUtil::getGLOriginFormat(data.getFormat()), GLPixelUtil::getGLOriginDataType(data.getFormat()), data.getData()); break; case GL_TEXTURE_2D: case GL_TEXTURE_CUBE_MAP: glTexSubImage2D(mFaceTarget, mLevel, dest.left, dest.top, dest.getWidth(), dest.getHeight(), GLPixelUtil::getGLOriginFormat(data.getFormat()), GLPixelUtil::getGLOriginDataType(data.getFormat()), data.getData()); break; case GL_TEXTURE_3D: glTexSubImage3D( GL_TEXTURE_3D, mLevel, dest.left, dest.top, dest.front, dest.getWidth(), dest.getHeight(), dest.getDepth(), GLPixelUtil::getGLOriginFormat(data.getFormat()), GLPixelUtil::getGLOriginDataType(data.getFormat()), data.getData()); break; } } // Restore defaults glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0); glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); glPixelStorei(GL_UNPACK_ALIGNMENT, 4); BS_INC_RENDER_STAT_CAT(ResWrite, RenderStatObject_Texture); }
void GLTextureBuffer::upload(const PixelData& data, const PixelVolume& dest) { if ((mUsage & TU_DEPTHSTENCIL) != 0) { LOGERR("Writing to depth stencil texture from CPU not supported."); return; } glBindTexture(mTarget, mTextureID); BS_CHECK_GL_ERROR(); if(PixelUtil::isCompressed(data.getFormat())) { // Block-compressed data cannot be smaller than 4x4, and must be a multiple of 4 const UINT32 actualWidth = Math::divideAndRoundUp(std::max(mWidth, 4U), 4U) * 4U; const UINT32 actualHeight = Math::divideAndRoundUp(std::max(mHeight, 4U), 4U) * 4U; const UINT32 expectedRowPitch = actualWidth; const UINT32 expectedSlicePitch = actualWidth * actualHeight; const bool isConsecutive = data.getRowPitch() == expectedRowPitch && data.getSlicePitch() == expectedSlicePitch; if (data.getFormat() != mFormat || !isConsecutive) { LOGERR("Compressed images must be consecutive, in the source format"); return; } GLenum format = GLPixelUtil::getGLInternalFormat(mFormat, mHwGamma); switch(mTarget) { case GL_TEXTURE_1D: glCompressedTexSubImage1D(GL_TEXTURE_1D, mLevel, dest.left, dest.getWidth(), format, data.getConsecutiveSize(), data.getData()); BS_CHECK_GL_ERROR(); break; case GL_TEXTURE_2D: case GL_TEXTURE_CUBE_MAP: glCompressedTexSubImage2D(mFaceTarget, mLevel, dest.left, dest.top, dest.getWidth(), dest.getHeight(), format, data.getConsecutiveSize(), data.getData()); BS_CHECK_GL_ERROR(); break; case GL_TEXTURE_3D: glCompressedTexSubImage3D(GL_TEXTURE_3D, mLevel, dest.left, dest.top, dest.front, dest.getWidth(), dest.getHeight(), dest.getDepth(), format, data.getConsecutiveSize(), data.getData()); BS_CHECK_GL_ERROR(); break; default: break; } } else { if (data.getWidth() != data.getRowPitch()) { glPixelStorei(GL_UNPACK_ROW_LENGTH, data.getRowPitch()); BS_CHECK_GL_ERROR(); } if (data.getHeight()*data.getWidth() != data.getSlicePitch()) { glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, (data.getSlicePitch() / data.getWidth())); BS_CHECK_GL_ERROR(); } if (data.getLeft() > 0 || data.getTop() > 0 || data.getFront() > 0) { glPixelStorei( GL_UNPACK_SKIP_PIXELS, data.getLeft() + data.getRowPitch() * data.getTop() + data.getSlicePitch() * data.getFront()); BS_CHECK_GL_ERROR(); } if ((data.getWidth()*PixelUtil::getNumElemBytes(data.getFormat())) & 3) { glPixelStorei(GL_UNPACK_ALIGNMENT, 1); BS_CHECK_GL_ERROR(); } switch(mTarget) { case GL_TEXTURE_1D: glTexSubImage1D(GL_TEXTURE_1D, mLevel, dest.left, dest.getWidth(), GLPixelUtil::getGLOriginFormat(data.getFormat()), GLPixelUtil::getGLOriginDataType(data.getFormat()), data.getData()); BS_CHECK_GL_ERROR(); break; case GL_TEXTURE_2D: case GL_TEXTURE_CUBE_MAP: glTexSubImage2D(mFaceTarget, mLevel, dest.left, dest.top, dest.getWidth(), dest.getHeight(), GLPixelUtil::getGLOriginFormat(data.getFormat()), GLPixelUtil::getGLOriginDataType(data.getFormat()), data.getData()); BS_CHECK_GL_ERROR(); break; case GL_TEXTURE_2D_ARRAY: case GL_TEXTURE_3D: glTexSubImage3D( mTarget, mLevel, dest.left, dest.top, dest.front, dest.getWidth(), dest.getHeight(), dest.getDepth(), GLPixelUtil::getGLOriginFormat(data.getFormat()), GLPixelUtil::getGLOriginDataType(data.getFormat()), data.getData()); BS_CHECK_GL_ERROR(); break; } } // Restore defaults glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); BS_CHECK_GL_ERROR(); glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0); BS_CHECK_GL_ERROR(); glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); BS_CHECK_GL_ERROR(); glPixelStorei(GL_UNPACK_ALIGNMENT, 4); BS_CHECK_GL_ERROR(); BS_INC_RENDER_STAT_CAT(ResWrite, RenderStatObject_Texture); }