diff options
Diffstat (limited to 'dom/canvas/WebGLTexture.h')
-rw-r--r-- | dom/canvas/WebGLTexture.h | 348 |
1 files changed, 348 insertions, 0 deletions
diff --git a/dom/canvas/WebGLTexture.h b/dom/canvas/WebGLTexture.h new file mode 100644 index 0000000000..8a451a9277 --- /dev/null +++ b/dom/canvas/WebGLTexture.h @@ -0,0 +1,348 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef WEBGL_TEXTURE_H_ +#define WEBGL_TEXTURE_H_ + +#include <algorithm> +#include <map> +#include <set> +#include <vector> + +#include "mozilla/Assertions.h" +#include "mozilla/Casting.h" +#include "mozilla/CheckedInt.h" +#include "mozilla/dom/TypedArray.h" + +#include "CacheInvalidator.h" +#include "WebGLObjectModel.h" +#include "WebGLStrongTypes.h" +#include "WebGLTypes.h" + +namespace mozilla { +class ErrorResult; +class WebGLContext; +class WebGLFramebuffer; +class WebGLSampler; +struct FloatOrInt; +struct TexImageSource; + +namespace dom { +class Element; +class HTMLVideoElement; +class ImageData; +class ArrayBufferViewOrSharedArrayBufferView; +} // namespace dom + +namespace layers { +class Image; +} // namespace layers + +namespace webgl { +struct DriverUnpackInfo; +struct FormatUsageInfo; +struct PackingInfo; +class TexUnpackBlob; +} // namespace webgl + +bool DoesTargetMatchDimensions(WebGLContext* webgl, TexImageTarget target, + uint8_t dims); + +namespace webgl { + +struct SamplingState final { + // Only store that which changes validation. + TexMinFilter minFilter = LOCAL_GL_NEAREST_MIPMAP_LINEAR; + TexMagFilter magFilter = LOCAL_GL_LINEAR; + TexWrap wrapS = LOCAL_GL_REPEAT; + TexWrap wrapT = LOCAL_GL_REPEAT; + // TexWrap wrapR = LOCAL_GL_REPEAT; + // GLfloat minLod = -1000; + // GLfloat maxLod = 1000; + TexCompareMode compareMode = LOCAL_GL_NONE; + // TexCompareFunc compareFunc = LOCAL_GL_LEQUAL; +}; + +struct ImageInfo final { + static const ImageInfo kUndefined; + + const webgl::FormatUsageInfo* mFormat = nullptr; + uint32_t mWidth = 0; + uint32_t mHeight = 0; + uint32_t mDepth = 0; + mutable Maybe<std::vector<bool>> mUninitializedSlices; + uint8_t mSamples = 0; + + // - + + size_t MemoryUsage() const; + + bool IsDefined() const { + if (!mFormat) { + MOZ_ASSERT(!mWidth && !mHeight && !mDepth); + return false; + } + + return true; + } + + Maybe<ImageInfo> NextMip(GLenum target) const; +}; + +} // namespace webgl + +class WebGLTexture final : public WebGLContextBoundObject, + public CacheInvalidator { + // Friends + friend class WebGLContext; + friend class WebGLFramebuffer; + + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(WebGLTexture, override) + + //////////////////////////////////// + // Members + public: + const GLuint mGLName; + + protected: + TexTarget mTarget; + + static const uint8_t kMaxFaceCount = 6; + uint8_t mFaceCount; // 6 for cube maps, 1 otherwise. + + bool mImmutable; // Set by texStorage* + uint8_t mImmutableLevelCount; + + uint32_t mBaseMipmapLevel; // Set by texParameter (defaults to 0) + uint32_t mMaxMipmapLevel; // Set by texParameter (defaults to 1000) + // You almost certainly don't want to query mMaxMipmapLevel. + // You almost certainly want MaxEffectiveMipmapLevel(). + + // These "dirty" flags are set when the level is updated (eg indirectly by + // clamping) and cleared when we tell the driver. + enum MipmapLevelState : uint8_t { + MIPMAP_LEVEL_DEFAULT, + MIPMAP_LEVEL_CLEAN, + MIPMAP_LEVEL_DIRTY + }; + MipmapLevelState mBaseMipmapLevelState = MIPMAP_LEVEL_DEFAULT; + MipmapLevelState mMaxMipmapLevelState = MIPMAP_LEVEL_DEFAULT; + + webgl::SamplingState mSamplingState; + + mutable const GLint* mCurSwizzle = + nullptr; // nullptr means 'default swizzle'. + + // - + + struct CompletenessInfo final { + uint8_t levels = 0; + bool powerOfTwo = false; + bool mipmapComplete = false; + const webgl::FormatUsageInfo* usage = nullptr; + const char* incompleteReason = nullptr; + }; + + mutable CacheWeakMap<const WebGLSampler*, webgl::SampleableInfo> + mSamplingCache; + + public: + Maybe<const CompletenessInfo> CalcCompletenessInfo( + bool ensureInit, bool skipMips = false) const; + Maybe<const webgl::SampleableInfo> CalcSampleableInfo( + const WebGLSampler*) const; + + const webgl::SampleableInfo* GetSampleableInfo(const WebGLSampler*) const; + + // - + + const auto& Immutable() const { return mImmutable; } + const auto& ImmutableLevelCount() const { return mImmutableLevelCount; } + + // ES3.0 p150 + uint32_t Es3_level_base() const { + const auto level_prime_base = mBaseMipmapLevel; + const auto level_immut = mImmutableLevelCount; + + if (!mImmutable) return level_prime_base; + return std::min(level_prime_base, level_immut - 1u); + } + uint32_t Es3_level_max() const { + const auto level_base = Es3_level_base(); + const auto level_prime_max = mMaxMipmapLevel; + const auto level_immut = mImmutableLevelCount; + + if (!mImmutable) return level_prime_max; + return std::min(std::max(level_base, level_prime_max), level_immut - 1u); + } + + // GLES 3.0.5 p158: `q` + uint32_t Es3_q() const; // "effective max mip level" + + // - + + const auto& FaceCount() const { return mFaceCount; } + + // We can just max this out to 31, which is the number of unsigned bits in + // GLsizei. + static const uint8_t kMaxLevelCount = 31; + + // We store information about the various images that are part of this + // texture. (cubemap faces, mipmap levels) + webgl::ImageInfo mImageInfoArr[kMaxLevelCount * kMaxFaceCount]; + + //////////////////////////////////// + + WebGLTexture(WebGLContext* webgl, GLuint tex); + + TexTarget Target() const { return mTarget; } + + protected: + ~WebGLTexture() override; + + public: + //////////////////////////////////// + // GL calls + bool BindTexture(TexTarget texTarget); + void GenerateMipmap(); + Maybe<double> GetTexParameter(GLenum pname) const; + void TexParameter(TexTarget texTarget, GLenum pname, const FloatOrInt& param); + + //////////////////////////////////// + // WebGLTextureUpload.cpp + + protected: + void TexOrSubImageBlob(bool isSubImage, TexImageTarget target, GLint level, + GLenum internalFormat, GLint xOffset, GLint yOffset, + GLint zOffset, const webgl::PackingInfo& pi, + const webgl::TexUnpackBlob* blob); + + bool ValidateTexImageSpecification(TexImageTarget target, uint32_t level, + const uvec3& size, + webgl::ImageInfo** const out_imageInfo); + bool ValidateTexImageSelection(TexImageTarget target, uint32_t level, + const uvec3& offset, const uvec3& size, + webgl::ImageInfo** const out_imageInfo); + + bool ValidateUnpack(const webgl::TexUnpackBlob* blob, bool isFunc3D, + const webgl::PackingInfo& srcPI) const; + + public: + void TexStorage(TexTarget target, uint32_t levels, GLenum sizedFormat, + const uvec3& size); + + // TexSubImage iff `!respecFormat` + void TexImage(uint32_t level, GLenum respecFormat, const uvec3& offset, + const webgl::PackingInfo& pi, const webgl::TexUnpackBlobDesc&); + + // CompressedTexSubImage iff `sub` + void CompressedTexImage(bool sub, GLenum imageTarget, uint32_t level, + GLenum formatEnum, const uvec3& offset, + const uvec3& size, const Range<const uint8_t>& src, + const uint32_t pboImageSize, + const Maybe<uint64_t>& pboOffset); + + // CopyTexSubImage iff `!respecFormat` + void CopyTexImage(GLenum imageTarget, uint32_t level, GLenum respecFormat, + const uvec3& dstOffset, const ivec2& srcOffset, + const uvec2& size2); + + //////////////////////////////////// + + protected: + void ClampLevelBaseAndMax(); + void RefreshSwizzle() const; + + static uint8_t FaceForTarget(TexImageTarget texImageTarget) { + GLenum rawTexImageTarget = texImageTarget.get(); + switch (rawTexImageTarget) { + case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + return AutoAssertCast(rawTexImageTarget - + LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X); + + default: + return 0; + } + } + + public: + auto& ImageInfoAtFace(uint8_t face, uint32_t level) { + MOZ_ASSERT(face < mFaceCount); + MOZ_ASSERT(level < kMaxLevelCount); + size_t pos = (level * mFaceCount) + face; + return mImageInfoArr[pos]; + } + + const auto& ImageInfoAtFace(uint8_t face, uint32_t level) const { + return const_cast<WebGLTexture*>(this)->ImageInfoAtFace(face, level); + } + + auto& ImageInfoAt(TexImageTarget texImageTarget, GLint level) { + const auto& face = FaceForTarget(texImageTarget); + return ImageInfoAtFace(face, level); + } + + const auto& ImageInfoAt(TexImageTarget texImageTarget, GLint level) const { + return const_cast<WebGLTexture*>(this)->ImageInfoAt(texImageTarget, level); + } + + const auto& BaseImageInfo() const { + if (mBaseMipmapLevel >= kMaxLevelCount) return webgl::ImageInfo::kUndefined; + + return ImageInfoAtFace(0, mBaseMipmapLevel); + } + + size_t MemoryUsage() const; + + bool EnsureImageDataInitialized(TexImageTarget target, uint32_t level); + void PopulateMipChain(uint32_t maxLevel); + bool IsMipAndCubeComplete(uint32_t maxLevel, bool ensureInit, + bool* out_initFailed) const; + void Truncate(); + + bool IsCubeMap() const { return (mTarget == LOCAL_GL_TEXTURE_CUBE_MAP); } +}; + +inline TexImageTarget TexImageTargetForTargetAndFace(TexTarget target, + uint8_t face) { + switch (target.get()) { + case LOCAL_GL_TEXTURE_2D: + case LOCAL_GL_TEXTURE_3D: + MOZ_ASSERT(face == 0); + return target.get(); + case LOCAL_GL_TEXTURE_CUBE_MAP: + MOZ_ASSERT(face < 6); + return LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + face; + default: + MOZ_CRASH("GFX: TexImageTargetForTargetAndFace"); + } +} + +already_AddRefed<mozilla::layers::Image> ImageFromVideo( + dom::HTMLVideoElement* elem); + +bool IsTarget3D(TexImageTarget target); + +GLenum DoTexImage(gl::GLContext* gl, TexImageTarget target, GLint level, + const webgl::DriverUnpackInfo* dui, GLsizei width, + GLsizei height, GLsizei depth, const void* data); +GLenum DoTexSubImage(gl::GLContext* gl, TexImageTarget target, GLint level, + GLint xOffset, GLint yOffset, GLint zOffset, GLsizei width, + GLsizei height, GLsizei depth, + const webgl::PackingInfo& pi, const void* data); +GLenum DoCompressedTexSubImage(gl::GLContext* gl, TexImageTarget target, + GLint level, GLint xOffset, GLint yOffset, + GLint zOffset, GLsizei width, GLsizei height, + GLsizei depth, GLenum sizedUnpackFormat, + GLsizei dataSize, const void* data); + +} // namespace mozilla + +#endif // WEBGL_TEXTURE_H_ |