gl::Error TextureGL::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, const gl::PixelUnpackState &unpack, size_t imageSize, const uint8_t *pixels) { ASSERT(CompatibleTextureTarget(mState.mTarget, target)); nativegl::CompressedTexImageFormat compressedTexImageFormat = nativegl::GetCompressedTexImageFormat(mFunctions, mWorkarounds, internalFormat); mStateManager->bindTexture(mState.mTarget, mTextureID); if (UseTexImage2D(mState.mTarget)) { ASSERT(size.depth == 1); mFunctions->compressedTexImage2D(target, static_cast<GLint>(level), compressedTexImageFormat.internalFormat, size.width, size.height, 0, static_cast<GLsizei>(imageSize), pixels); } else if (UseTexImage3D(mState.mTarget)) { mFunctions->compressedTexImage3D( target, static_cast<GLint>(level), compressedTexImageFormat.internalFormat, size.width, size.height, size.depth, 0, static_cast<GLsizei>(imageSize), pixels); } else { UNREACHABLE(); } mLevelInfo[level] = GetLevelInfo(internalFormat, compressedTexImageFormat.internalFormat); ASSERT(!mLevelInfo[level].lumaWorkaround.enabled); return gl::Error(GL_NO_ERROR); }
gl::Error TextureGL::setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, const gl::PixelUnpackState &unpack, size_t imageSize, const uint8_t *pixels) { ASSERT(CompatibleTextureTarget(mState.mTarget, target)); nativegl::CompressedTexSubImageFormat compressedTexSubImageFormat = nativegl::GetCompressedSubTexImageFormat(mFunctions, mWorkarounds, format); mStateManager->bindTexture(mState.mTarget, mTextureID); if (UseTexImage2D(mState.mTarget)) { ASSERT(area.z == 0 && area.depth == 1); mFunctions->compressedTexSubImage2D( target, static_cast<GLint>(level), area.x, area.y, area.width, area.height, compressedTexSubImageFormat.format, static_cast<GLsizei>(imageSize), pixels); } else if (UseTexImage3D(mState.mTarget)) { mFunctions->compressedTexSubImage3D(target, static_cast<GLint>(level), area.x, area.y, area.z, area.width, area.height, area.depth, compressedTexSubImageFormat.format, static_cast<GLsizei>(imageSize), pixels); } else { UNREACHABLE(); } ASSERT(!mLevelInfo[level].lumaWorkaround.enabled && !GetLevelInfo(format, compressedTexSubImageFormat.format).lumaWorkaround.enabled); return gl::Error(GL_NO_ERROR); }
gl::Error TextureGL::copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea, const gl::Framebuffer *source) { const FramebufferGL *sourceFramebufferGL = GetImplAs<FramebufferGL>(source); mStateManager->bindTexture(mTextureType, mTextureID); mStateManager->bindFramebuffer(GL_READ_FRAMEBUFFER, sourceFramebufferGL->getFramebufferID()); if (UseTexImage2D(mTextureType)) { ASSERT(destOffset.z == 0); mFunctions->copyTexSubImage2D(target, static_cast<GLint>(level), destOffset.x, destOffset.y, sourceArea.x, sourceArea.y, sourceArea.width, sourceArea.height); } else if (UseTexImage3D(mTextureType)) { mFunctions->copyTexSubImage3D(target, static_cast<GLint>(level), destOffset.x, destOffset.y, destOffset.z, sourceArea.x, sourceArea.y, sourceArea.width, sourceArea.height); } else { UNREACHABLE(); } return gl::Error(GL_NO_ERROR); }
gl::Error TextureGL::setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const uint8_t *pixels) { ASSERT(CompatibleTextureTarget(mTextureType, target)); nativegl::TexSubImageFormat texSubImageFormat = nativegl::GetTexSubImageFormat(mFunctions, mWorkarounds, format, type); mStateManager->bindTexture(mTextureType, mTextureID); if (UseTexImage2D(mTextureType)) { ASSERT(area.z == 0 && area.depth == 1); mFunctions->texSubImage2D(target, static_cast<GLint>(level), area.x, area.y, area.width, area.height, texSubImageFormat.format, texSubImageFormat.type, pixels); } else if (UseTexImage3D(mTextureType)) { mFunctions->texSubImage3D(target, static_cast<GLint>(level), area.x, area.y, area.z, area.width, area.height, area.depth, texSubImageFormat.format, texSubImageFormat.type, pixels); } else { UNREACHABLE(); } return gl::Error(GL_NO_ERROR); }
gl::Error TextureGL::copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea, const gl::Framebuffer *source) { const FramebufferGL *sourceFramebufferGL = GetImplAs<FramebufferGL>(source); mStateManager->bindTexture(mState.mTarget, mTextureID); mStateManager->bindFramebuffer(GL_READ_FRAMEBUFFER, sourceFramebufferGL->getFramebufferID()); const LevelInfoGL &levelInfo = mLevelInfo[level]; if (levelInfo.lumaWorkaround.enabled) { gl::Error error = mBlitter->copySubImageToLUMAWorkaroundTexture( mTextureID, mState.mTarget, target, levelInfo.sourceFormat, level, destOffset, sourceArea, source); if (error.isError()) { return error; } } else { if (UseTexImage2D(mState.mTarget)) { ASSERT(destOffset.z == 0); mFunctions->copyTexSubImage2D(target, static_cast<GLint>(level), destOffset.x, destOffset.y, sourceArea.x, sourceArea.y, sourceArea.width, sourceArea.height); } else if (UseTexImage3D(mState.mTarget)) { mFunctions->copyTexSubImage3D(target, static_cast<GLint>(level), destOffset.x, destOffset.y, destOffset.z, sourceArea.x, sourceArea.y, sourceArea.width, sourceArea.height); } else { UNREACHABLE(); } } return gl::Error(GL_NO_ERROR); }
gl::Error TextureGL::copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat, const gl::Framebuffer *source) { nativegl::CopyTexImageImageFormat copyTexImageFormat = nativegl::GetCopyTexImageImageFormat( mFunctions, mWorkarounds, internalFormat, source->getImplementationColorReadType()); LevelInfoGL levelInfo = GetLevelInfo(internalFormat, copyTexImageFormat.internalFormat); if (levelInfo.lumaWorkaround.enabled) { gl::Error error = mBlitter->copyImageToLUMAWorkaroundTexture( mTextureID, mState.mTarget, target, levelInfo.sourceFormat, level, sourceArea, copyTexImageFormat.internalFormat, source); if (error.isError()) { return error; } } else { const FramebufferGL *sourceFramebufferGL = GetImplAs<FramebufferGL>(source); mStateManager->bindTexture(mState.mTarget, mTextureID); mStateManager->bindFramebuffer(GL_READ_FRAMEBUFFER, sourceFramebufferGL->getFramebufferID()); if (UseTexImage2D(mState.mTarget)) { mFunctions->copyTexImage2D(target, static_cast<GLint>(level), copyTexImageFormat.internalFormat, sourceArea.x, sourceArea.y, sourceArea.width, sourceArea.height, 0); } else { UNREACHABLE(); } } mLevelInfo[level] = levelInfo; return gl::Error(GL_NO_ERROR); }
gl::Error TextureGL::setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const uint8_t *pixels) { ASSERT(CompatibleTextureTarget(mState.mTarget, target)); nativegl::TexSubImageFormat texSubImageFormat = nativegl::GetTexSubImageFormat(mFunctions, mWorkarounds, format, type); mStateManager->bindTexture(mState.mTarget, mTextureID); if (mWorkarounds.unpackOverlappingRowsSeparatelyUnpackBuffer && unpack.pixelBuffer.get() && unpack.rowLength != 0 && unpack.rowLength < area.width) { ANGLE_TRY(setSubImageRowByRowWorkaround(target, level, area, format, type, unpack, pixels)); } else if (UseTexImage2D(mState.mTarget)) { ASSERT(area.z == 0 && area.depth == 1); mFunctions->texSubImage2D(target, static_cast<GLint>(level), area.x, area.y, area.width, area.height, texSubImageFormat.format, texSubImageFormat.type, pixels); } else if (UseTexImage3D(mState.mTarget)) { mFunctions->texSubImage3D(target, static_cast<GLint>(level), area.x, area.y, area.z, area.width, area.height, area.depth, texSubImageFormat.format, texSubImageFormat.type, pixels); } else { UNREACHABLE(); } ASSERT(mLevelInfo[level].lumaWorkaround.enabled == GetLevelInfo(format, texSubImageFormat.format).lumaWorkaround.enabled); return gl::Error(GL_NO_ERROR); }
gl::Error TextureGL::copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat, const gl::Framebuffer *source) { const FramebufferGL *sourceFramebufferGL = GetImplAs<FramebufferGL>(source); mStateManager->bindTexture(mTextureType, mTextureID); mStateManager->bindFramebuffer(GL_READ_FRAMEBUFFER, sourceFramebufferGL->getFramebufferID()); nativegl::CopyTexImageImageFormat copyTexImageFormat = nativegl::GetCopyTexImageImageFormat( mFunctions, mWorkarounds, internalFormat, source->getImplementationColorReadType()); if (UseTexImage2D(mTextureType)) { mFunctions->copyTexImage2D(target, static_cast<GLint>(level), copyTexImageFormat.internalFormat, sourceArea.x, sourceArea.y, sourceArea.width, sourceArea.height, 0); } else { UNREACHABLE(); } return gl::Error(GL_NO_ERROR); }
gl::Error TextureGL::setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size) { // TODO: emulate texture storage with TexImage calls if on GL version <4.2 or the // ARB_texture_storage extension is not available. nativegl::TexStorageFormat texStorageFormat = nativegl::GetTexStorageFormat(mFunctions, mWorkarounds, internalFormat); mStateManager->bindTexture(mState.mTarget, mTextureID); if (UseTexImage2D(mState.mTarget)) { ASSERT(size.depth == 1); if (mFunctions->texStorage2D) { mFunctions->texStorage2D(target, static_cast<GLsizei>(levels), texStorageFormat.internalFormat, size.width, size.height); } else { // Make sure no pixel unpack buffer is bound mStateManager->bindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat); // Internal format must be sized ASSERT(internalFormatInfo.pixelBytes != 0); for (size_t level = 0; level < levels; level++) { gl::Extents levelSize(std::max(size.width >> level, 1), std::max(size.height >> level, 1), 1); if (mState.mTarget == GL_TEXTURE_2D) { if (internalFormatInfo.compressed) { GLuint dataSize = 0; ANGLE_TRY_RESULT(internalFormatInfo.computeCompressedImageSize( GL_UNSIGNED_BYTE, levelSize), dataSize); mFunctions->compressedTexImage2D(target, static_cast<GLint>(level), texStorageFormat.internalFormat, levelSize.width, levelSize.height, 0, static_cast<GLsizei>(dataSize), nullptr); } else { mFunctions->texImage2D(target, static_cast<GLint>(level), texStorageFormat.internalFormat, levelSize.width, levelSize.height, 0, internalFormatInfo.format, internalFormatInfo.type, nullptr); } } else if (mState.mTarget == GL_TEXTURE_CUBE_MAP) { for (GLenum face = gl::FirstCubeMapTextureTarget; face <= gl::LastCubeMapTextureTarget; face++) { if (internalFormatInfo.compressed) { GLuint dataSize = 0; ANGLE_TRY_RESULT(internalFormatInfo.computeCompressedImageSize( GL_UNSIGNED_BYTE, levelSize), dataSize); mFunctions->compressedTexImage2D( face, static_cast<GLint>(level), texStorageFormat.internalFormat, levelSize.width, levelSize.height, 0, static_cast<GLsizei>(dataSize), nullptr); } else { mFunctions->texImage2D(face, static_cast<GLint>(level), texStorageFormat.internalFormat, levelSize.width, levelSize.height, 0, internalFormatInfo.format, internalFormatInfo.type, nullptr); } } } else { UNREACHABLE(); } } } }
gl::Error TextureGL::setSubImageRowByRowWorkaround(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const uint8_t *pixels) { gl::PixelUnpackState unpackToUse; unpackToUse.pixelBuffer = unpack.pixelBuffer; mStateManager->setPixelUnpackState(unpackToUse); unpackToUse.pixelBuffer.set(nullptr); GLenum sizedFormat = gl::GetSizedInternalFormat(mState.getImageDesc(mState.mTarget, level).internalFormat, type); const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedFormat); GLuint rowBytes = 0; ANGLE_TRY_RESULT( formatInfo.computeRowPitch(GL_NONE, area.width, unpack.alignment, unpack.rowLength), rowBytes); GLuint imageBytes = 0; ANGLE_TRY_RESULT( formatInfo.computeDepthPitch(GL_NONE, area.width, area.height, unpack.alignment, unpack.rowLength, unpack.imageHeight), imageBytes); bool useTexImage3D = UseTexImage3D(mState.mTarget); GLuint skipBytes = 0; ANGLE_TRY_RESULT(formatInfo.computeSkipBytes(rowBytes, imageBytes, unpack.skipImages, unpack.skipRows, unpack.skipPixels, useTexImage3D), skipBytes); const uint8_t *pixelsWithSkip = pixels + skipBytes; if (useTexImage3D) { for (GLint image = 0; image < area.depth; ++image) { GLint imageByteOffset = image * imageBytes; for (GLint row = 0; row < area.height; ++row) { GLint byteOffset = imageByteOffset + row * rowBytes; const GLubyte *rowPixels = pixelsWithSkip + byteOffset; mFunctions->texSubImage3D(target, static_cast<GLint>(level), area.x, row + area.y, image + area.z, area.width, 1, 1, format, type, rowPixels); } } } else if (UseTexImage2D(mState.mTarget)) { for (GLint row = 0; row < area.height; ++row) { GLint byteOffset = row * rowBytes; const GLubyte *rowPixels = pixelsWithSkip + byteOffset; mFunctions->texSubImage2D(target, static_cast<GLint>(level), area.x, row + area.y, area.width, 1, format, type, rowPixels); } } else { UNREACHABLE(); } return gl::NoError(); }