summaryrefslogtreecommitdiffstats
path: root/dom/canvas/WebGLTexture.h
diff options
context:
space:
mode:
Diffstat (limited to 'dom/canvas/WebGLTexture.h')
-rw-r--r--dom/canvas/WebGLTexture.h444
1 files changed, 444 insertions, 0 deletions
diff --git a/dom/canvas/WebGLTexture.h b/dom/canvas/WebGLTexture.h
new file mode 100644
index 000000000..66e781f23
--- /dev/null
+++ b/dom/canvas/WebGLTexture.h
@@ -0,0 +1,444 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* 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/CheckedInt.h"
+#include "mozilla/dom/TypedArray.h"
+#include "mozilla/LinkedList.h"
+#include "nsWrapperCache.h"
+
+#include "WebGLFramebufferAttachable.h"
+#include "WebGLObjectModel.h"
+#include "WebGLStrongTypes.h"
+#include "WebGLTypes.h"
+
+namespace mozilla {
+class ErrorResult;
+class WebGLContext;
+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,
+ const char* funcName);
+
+
+// NOTE: When this class is switched to new DOM bindings, update the (then-slow)
+// WrapObject calls in GetParameter and GetFramebufferAttachmentParameter.
+class WebGLTexture final
+ : public nsWrapperCache
+ , public WebGLRefCountedObject<WebGLTexture>
+ , public LinkedListElement<WebGLTexture>
+{
+ // Friends
+ friend class WebGLContext;
+ friend class WebGLFramebuffer;
+
+ ////////////////////////////////////
+ // Members
+public:
+ const GLuint mGLName;
+
+protected:
+ TexTarget mTarget;
+
+ static const uint8_t kMaxFaceCount = 6;
+ uint8_t mFaceCount; // 6 for cube maps, 1 otherwise.
+
+ TexMinFilter mMinFilter;
+ TexMagFilter mMagFilter;
+ TexWrap mWrapS, mWrapT;
+
+ 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().
+
+ GLenum mTexCompareMode;
+
+ // Resolvable optimizations:
+ bool mIsResolved;
+ FakeBlackType mResolved_FakeBlack;
+ const GLint* mResolved_Swizzle; // nullptr means 'default swizzle'.
+
+public:
+ class ImageInfo;
+
+ // numLevels = log2(size) + 1
+ // numLevels(16k) = log2(16k) + 1 = 14 + 1 = 15
+ // numLevels(1M) = log2(1M) + 1 = 19.9 + 1 ~= 21
+ // Or we can just max this out to 31, which is the number of unsigned bits in GLsizei.
+ static const uint8_t kMaxLevelCount = 31;
+
+ // And in turn, it needs these forwards:
+protected:
+ // We need to forward these.
+ void SetImageInfo(ImageInfo* target, const ImageInfo& newInfo);
+ void SetImageInfosAtLevel(uint32_t level, const ImageInfo& newInfo);
+
+public:
+ // We store information about the various images that are part of this
+ // texture. (cubemap faces, mipmap levels)
+ class ImageInfo
+ {
+ friend void WebGLTexture::SetImageInfo(ImageInfo* target,
+ const ImageInfo& newInfo);
+ friend void WebGLTexture::SetImageInfosAtLevel(uint32_t level,
+ const ImageInfo& newInfo);
+
+ public:
+ static const ImageInfo kUndefined;
+
+ // This is the "effective internal format" of the texture, an official
+ // OpenGL spec concept, see OpenGL ES 3.0.3 spec, section 3.8.3, page
+ // 126 and below.
+ const webgl::FormatUsageInfo* const mFormat;
+
+ const uint32_t mWidth;
+ const uint32_t mHeight;
+ const uint32_t mDepth;
+
+ protected:
+ bool mIsDataInitialized;
+
+ std::set<WebGLFBAttachPoint*> mAttachPoints;
+
+ public:
+ ImageInfo()
+ : mFormat(LOCAL_GL_NONE)
+ , mWidth(0)
+ , mHeight(0)
+ , mDepth(0)
+ , mIsDataInitialized(false)
+ { }
+
+ ImageInfo(const webgl::FormatUsageInfo* format, uint32_t width, uint32_t height,
+ uint32_t depth, bool isDataInitialized)
+ : mFormat(format)
+ , mWidth(width)
+ , mHeight(height)
+ , mDepth(depth)
+ , mIsDataInitialized(isDataInitialized)
+ {
+ MOZ_ASSERT(mFormat);
+ }
+
+ void Clear();
+
+ ~ImageInfo() {
+ if (!IsDefined())
+ Clear();
+ }
+
+ protected:
+ ImageInfo& operator =(const ImageInfo& a);
+
+ public:
+ uint32_t PossibleMipmapLevels() const {
+ // GLES 3.0.4, 3.8 - Mipmapping: `floor(log2(largest_of_dims)) + 1`
+ const uint32_t largest = std::max(std::max(mWidth, mHeight), mDepth);
+ MOZ_ASSERT(largest != 0);
+ return FloorLog2Size(largest) + 1;
+ }
+
+ bool IsPowerOfTwo() const;
+
+ void AddAttachPoint(WebGLFBAttachPoint* attachPoint);
+ void RemoveAttachPoint(WebGLFBAttachPoint* attachPoint);
+ void OnRespecify() const;
+
+ size_t MemoryUsage() const;
+
+ bool IsDefined() const {
+ if (mFormat == LOCAL_GL_NONE) {
+ MOZ_ASSERT(!mWidth && !mHeight && !mDepth);
+ return false;
+ }
+
+ return true;
+ }
+
+ bool IsDataInitialized() const { return mIsDataInitialized; }
+
+ void SetIsDataInitialized(bool isDataInitialized, WebGLTexture* tex);
+ };
+
+ ImageInfo mImageInfoArr[kMaxLevelCount * kMaxFaceCount];
+
+ ////////////////////////////////////
+public:
+ NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLTexture)
+ NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLTexture)
+
+ WebGLTexture(WebGLContext* webgl, GLuint tex);
+
+ void Delete();
+
+ bool HasEverBeenBound() const { return mTarget != LOCAL_GL_NONE; }
+ TexTarget Target() const { return mTarget; }
+
+ WebGLContext* GetParentObject() const {
+ return mContext;
+ }
+
+ virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override;
+
+protected:
+ ~WebGLTexture() {
+ DeleteOnce();
+ }
+
+public:
+ ////////////////////////////////////
+ // GL calls
+ bool BindTexture(TexTarget texTarget);
+ void GenerateMipmap(TexTarget texTarget);
+ JS::Value GetTexParameter(TexTarget texTarget, GLenum pname);
+ bool IsTexture() const;
+ void TexParameter(TexTarget texTarget, GLenum pname, const FloatOrInt& param);
+
+ ////////////////////////////////////
+ // WebGLTextureUpload.cpp
+
+protected:
+ void TexOrSubImageBlob(bool isSubImage, const char* funcName, TexImageTarget target,
+ GLint level, GLenum internalFormat, GLint xOffset,
+ GLint yOffset, GLint zOffset,
+ const webgl::PackingInfo& pi,
+ const webgl::TexUnpackBlob* blob);
+
+ bool ValidateTexImageSpecification(const char* funcName, TexImageTarget target,
+ GLint level, uint32_t width, uint32_t height,
+ uint32_t depth,
+ WebGLTexture::ImageInfo** const out_imageInfo);
+ bool ValidateTexImageSelection(const char* funcName, TexImageTarget target,
+ GLint level, GLint xOffset, GLint yOffset,
+ GLint zOffset, uint32_t width, uint32_t height,
+ uint32_t depth,
+ WebGLTexture::ImageInfo** const out_imageInfo);
+ bool ValidateCopyTexImageForFeedback(const char* funcName, uint32_t level, GLint layer = 0) const;
+
+ bool ValidateUnpack(const char* funcName, const webgl::TexUnpackBlob* blob,
+ bool isFunc3D, const webgl::PackingInfo& srcPI) const;
+public:
+ void TexStorage(const char* funcName, TexTarget target, GLsizei levels,
+ GLenum sizedFormat, GLsizei width, GLsizei height, GLsizei depth);
+ void TexImage(const char* funcName, TexImageTarget target, GLint level,
+ GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth,
+ GLint border, const webgl::PackingInfo& pi, const TexImageSource& src);
+ void TexSubImage(const char* funcName, TexImageTarget target, GLint level,
+ GLint xOffset, GLint yOffset, GLint zOffset, GLsizei width,
+ GLsizei height, GLsizei depth, const webgl::PackingInfo& pi,
+ const TexImageSource& src);
+protected:
+ void TexImage(const char* funcName, TexImageTarget target, GLint level,
+ GLenum internalFormat, const webgl::PackingInfo& pi,
+ const webgl::TexUnpackBlob* blob);
+ void TexSubImage(const char* funcName, TexImageTarget target, GLint level,
+ GLint xOffset, GLint yOffset, GLint zOffset,
+ const webgl::PackingInfo& pi, const webgl::TexUnpackBlob* blob);
+public:
+ void CompressedTexImage(const char* funcName, TexImageTarget target, GLint level,
+ GLenum internalFormat, GLsizei width, GLsizei height,
+ GLsizei depth, GLint border, const TexImageSource& src);
+ void CompressedTexSubImage(const char* funcName, TexImageTarget target, GLint level,
+ GLint xOffset, GLint yOffset, GLint zOffset, GLsizei width,
+ GLsizei height, GLsizei depth, GLenum sizedUnpackFormat,
+ const TexImageSource& src);
+
+ void CopyTexImage2D(TexImageTarget target, GLint level, GLenum internalFormat,
+ GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+ void CopyTexSubImage(const char* funcName, TexImageTarget target, GLint level,
+ GLint xOffset, GLint yOffset, GLint zOffset, GLint x, GLint y,
+ GLsizei width, GLsizei height);
+
+ ////////////////////////////////////
+
+protected:
+ void ClampLevelBaseAndMax();
+
+ void PopulateMipChain(uint32_t baseLevel, uint32_t maxLevel);
+
+ bool MaxEffectiveMipmapLevel(uint32_t texUnit, uint32_t* const out) 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 rawTexImageTarget - LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X;
+
+ default:
+ return 0;
+ }
+ }
+
+ ImageInfo& 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 ImageInfo& ImageInfoAtFace(uint8_t face, uint32_t level) const {
+ return const_cast<WebGLTexture*>(this)->ImageInfoAtFace(face, level);
+ }
+
+public:
+ ImageInfo& ImageInfoAt(TexImageTarget texImageTarget, GLint level) {
+ auto face = FaceForTarget(texImageTarget);
+ return ImageInfoAtFace(face, level);
+ }
+
+ const ImageInfo& ImageInfoAt(TexImageTarget texImageTarget, GLint level) const {
+ return const_cast<WebGLTexture*>(this)->ImageInfoAt(texImageTarget, level);
+ }
+
+ void SetImageInfoAt(TexImageTarget texImageTarget, GLint level,
+ const ImageInfo& val)
+ {
+ ImageInfo* target = &ImageInfoAt(texImageTarget, level);
+ SetImageInfo(target, val);
+ }
+
+ const ImageInfo& BaseImageInfo() const {
+ if (mBaseMipmapLevel >= kMaxLevelCount)
+ return ImageInfo::kUndefined;
+
+ return ImageInfoAtFace(0, mBaseMipmapLevel);
+ }
+
+ size_t MemoryUsage() const;
+
+ bool InitializeImageData(const char* funcName, TexImageTarget target, uint32_t level);
+protected:
+ bool EnsureImageDataInitialized(const char* funcName, TexImageTarget target,
+ uint32_t level);
+ bool EnsureLevelInitialized(const char* funcName, uint32_t level);
+
+ bool CheckFloatTextureFilterParams() const {
+ // Without OES_texture_float_linear, only NEAREST and
+ // NEAREST_MIMPAMP_NEAREST are supported.
+ return mMagFilter == LOCAL_GL_NEAREST &&
+ (mMinFilter == LOCAL_GL_NEAREST ||
+ mMinFilter == LOCAL_GL_NEAREST_MIPMAP_NEAREST);
+ }
+
+ bool AreBothWrapModesClampToEdge() const {
+ return mWrapS == LOCAL_GL_CLAMP_TO_EDGE &&
+ mWrapT == LOCAL_GL_CLAMP_TO_EDGE;
+ }
+
+public:
+ bool DoesMinFilterRequireMipmap() const {
+ return !(mMinFilter == LOCAL_GL_NEAREST ||
+ mMinFilter == LOCAL_GL_LINEAR);
+ }
+
+ void SetGeneratedMipmap();
+
+ void SetCustomMipmap();
+
+ bool AreAllLevel0ImageInfosEqual() const;
+
+ bool IsMipmapComplete(const char* funcName, uint32_t texUnit,
+ bool* const out_initFailed);
+
+ bool IsCubeComplete() const;
+
+ bool IsComplete(const char* funcName, uint32_t texUnit, const char** const out_reason,
+ bool* const out_initFailed);
+
+ bool IsMipmapCubeComplete() const;
+
+ bool IsCubeMap() const { return (mTarget == LOCAL_GL_TEXTURE_CUBE_MAP); }
+
+ // Resolve cache optimizations
+protected:
+ bool GetFakeBlackType(const char* funcName, uint32_t texUnit,
+ FakeBlackType* const out_fakeBlack);
+public:
+ bool IsFeedback(WebGLContext* webgl, const char* funcName, uint32_t texUnit,
+ const std::vector<const WebGLFBAttachPoint*>& fbAttachments) const;
+
+ bool ResolveForDraw(const char* funcName, uint32_t texUnit,
+ FakeBlackType* const out_fakeBlack);
+
+ void InvalidateResolveCache() { mIsResolved = false; }
+};
+
+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_