gecko-dev/dom/canvas/WebGLTexture.h

457 строки
16 KiB
C++

/* -*- 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;
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>
, public WebGLContextBoundObject
{
// 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, GLint* maybeIntParam,
GLfloat* maybeFloatParam);
////////////////////////////////////
// WebGLTextureUpload.cpp
void TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarget target,
GLint level, GLenum internalFormat, GLint xOffset, GLint yOffset,
GLint zOffset, GLsizei width, GLsizei height, GLsizei depth,
GLint border, GLenum unpackFormat, GLenum unpackType,
const dom::ArrayBufferView* view);
void TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarget target,
GLint level, GLenum internalFormat, GLint xOffset, GLint yOffset,
GLint zOffset, GLenum unpackFormat, GLenum unpackType,
const dom::ImageData& imageData);
void TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarget target,
GLint level, GLenum internalFormat, GLint xOffset, GLint yOffset,
GLint zOffset, GLenum unpackFormat, GLenum unpackType,
const dom::Element& elem, ErrorResult* const out_error);
void TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarget target,
GLint level, GLenum internalFormat, GLint xOffset, GLint yOffset,
GLint zOffset, GLsizei width, GLsizei height, GLsizei depth,
GLint border, GLenum unpackFormat, GLenum unpackType,
WebGLsizeiptr offset);
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) 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);
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 dom::ArrayBufferView& view);
void CompressedTexSubImage(const char* funcName, TexImageTarget target, GLint level,
GLint xOffset, GLint yOffset, GLint zOffset, GLsizei width,
GLsizei height, GLsizei depth, GLenum sizedUnpackFormat,
const dom::ArrayBufferView& view);
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 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(uint32_t texUnit) const;
bool IsCubeComplete() const;
bool IsComplete(uint32_t texUnit, const char** const out_reason) const;
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_