2012-12-03 16:13:47 -08:00
|
|
|
/* -*- 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 WEBGLTEXTURE_H_
|
|
|
|
#define WEBGLTEXTURE_H_
|
|
|
|
|
|
|
|
#include "WebGLObjectModel.h"
|
|
|
|
|
|
|
|
#include "nsWrapperCache.h"
|
|
|
|
|
|
|
|
#include "mozilla/LinkedList.h"
|
2013-01-15 04:22:03 -08:00
|
|
|
#include <algorithm>
|
2012-12-03 16:13:47 -08:00
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
|
|
|
|
// Zero is not an integer power of two.
|
2013-09-04 05:14:43 -07:00
|
|
|
inline bool is_pot_assuming_nonnegative(GLsizei x)
|
2012-12-03 16:13:47 -08:00
|
|
|
{
|
|
|
|
return x && (x & (x-1)) == 0;
|
|
|
|
}
|
|
|
|
|
2013-10-11 06:16:43 -07:00
|
|
|
inline bool FormatHasAlpha(GLenum format)
|
|
|
|
{
|
|
|
|
return format == LOCAL_GL_RGBA ||
|
|
|
|
format == LOCAL_GL_LUMINANCE_ALPHA ||
|
|
|
|
format == LOCAL_GL_ALPHA ||
|
|
|
|
format == LOCAL_GL_RGBA4 ||
|
|
|
|
format == LOCAL_GL_RGB5_A1;
|
|
|
|
}
|
|
|
|
|
2012-12-03 16:13:47 -08:00
|
|
|
// NOTE: When this class is switched to new DOM bindings, update the (then-slow)
|
|
|
|
// WrapObject calls in GetParameter and GetFramebufferAttachmentParameter.
|
|
|
|
class WebGLTexture MOZ_FINAL
|
2013-08-29 08:39:17 -07:00
|
|
|
: public nsWrapperCache
|
2012-12-03 16:13:47 -08:00
|
|
|
, public WebGLRefCountedObject<WebGLTexture>
|
|
|
|
, public LinkedListElement<WebGLTexture>
|
|
|
|
, public WebGLContextBoundObject
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
WebGLTexture(WebGLContext *context);
|
|
|
|
|
|
|
|
~WebGLTexture() {
|
|
|
|
DeleteOnce();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Delete();
|
|
|
|
|
2013-10-01 17:30:05 -07:00
|
|
|
bool HasEverBeenBound() const { return mHasEverBeenBound; }
|
2012-12-03 16:13:47 -08:00
|
|
|
void SetHasEverBeenBound(bool x) { mHasEverBeenBound = x; }
|
2013-10-01 17:30:05 -07:00
|
|
|
GLuint GLName() const { return mGLName; }
|
2012-12-03 16:13:47 -08:00
|
|
|
GLenum Target() const { return mTarget; }
|
|
|
|
|
|
|
|
WebGLContext *GetParentObject() const {
|
|
|
|
return Context();
|
|
|
|
}
|
|
|
|
|
2013-04-25 09:29:54 -07:00
|
|
|
virtual JSObject* WrapObject(JSContext *cx,
|
|
|
|
JS::Handle<JSObject*> scope) MOZ_OVERRIDE;
|
2012-12-03 16:13:47 -08:00
|
|
|
|
2013-08-29 08:39:17 -07:00
|
|
|
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLTexture)
|
|
|
|
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLTexture)
|
2012-12-03 16:13:47 -08:00
|
|
|
|
|
|
|
protected:
|
|
|
|
|
|
|
|
friend class WebGLContext;
|
|
|
|
friend class WebGLFramebuffer;
|
|
|
|
|
|
|
|
bool mHasEverBeenBound;
|
2013-09-04 05:14:43 -07:00
|
|
|
GLuint mGLName;
|
2012-12-03 16:13:47 -08:00
|
|
|
|
|
|
|
// we store information about the various images that are part of
|
|
|
|
// this texture (cubemap faces, mipmap levels)
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
2013-10-11 06:16:43 -07:00
|
|
|
class ImageInfo
|
|
|
|
: public WebGLRectangleObject
|
|
|
|
{
|
2012-12-03 16:13:47 -08:00
|
|
|
public:
|
|
|
|
ImageInfo()
|
|
|
|
: mFormat(0)
|
|
|
|
, mType(0)
|
2013-10-11 06:16:43 -07:00
|
|
|
, mImageDataStatus(WebGLImageDataStatus::NoImageData)
|
2012-12-03 16:13:47 -08:00
|
|
|
{}
|
|
|
|
|
2013-09-04 05:14:43 -07:00
|
|
|
ImageInfo(GLsizei width, GLsizei height,
|
2013-10-11 06:16:43 -07:00
|
|
|
GLenum format, GLenum type, WebGLImageDataStatus status)
|
2012-12-03 16:13:47 -08:00
|
|
|
: WebGLRectangleObject(width, height)
|
|
|
|
, mFormat(format)
|
|
|
|
, mType(type)
|
2013-10-11 06:16:43 -07:00
|
|
|
, mImageDataStatus(status)
|
|
|
|
{
|
|
|
|
// shouldn't use this constructor to construct a null ImageInfo
|
|
|
|
MOZ_ASSERT(status != WebGLImageDataStatus::NoImageData);
|
|
|
|
}
|
2012-12-03 16:13:47 -08:00
|
|
|
|
|
|
|
bool operator==(const ImageInfo& a) const {
|
2013-10-11 06:16:43 -07:00
|
|
|
return mImageDataStatus == a.mImageDataStatus &&
|
|
|
|
mWidth == a.mWidth &&
|
|
|
|
mHeight == a.mHeight &&
|
|
|
|
mFormat == a.mFormat &&
|
|
|
|
mType == a.mType;
|
2012-12-03 16:13:47 -08:00
|
|
|
}
|
|
|
|
bool operator!=(const ImageInfo& a) const {
|
|
|
|
return !(*this == a);
|
|
|
|
}
|
|
|
|
bool IsSquare() const {
|
|
|
|
return mWidth == mHeight;
|
|
|
|
}
|
|
|
|
bool IsPositive() const {
|
|
|
|
return mWidth > 0 && mHeight > 0;
|
|
|
|
}
|
|
|
|
bool IsPowerOfTwo() const {
|
|
|
|
return is_pot_assuming_nonnegative(mWidth) &&
|
|
|
|
is_pot_assuming_nonnegative(mHeight); // negative sizes should never happen (caught in texImage2D...)
|
|
|
|
}
|
2013-10-11 06:16:43 -07:00
|
|
|
bool HasUninitializedImageData() const {
|
|
|
|
return mImageDataStatus == WebGLImageDataStatus::UninitializedImageData;
|
|
|
|
}
|
2012-12-03 16:13:47 -08:00
|
|
|
int64_t MemoryUsage() const;
|
2013-09-04 05:14:43 -07:00
|
|
|
GLenum Format() const { return mFormat; }
|
|
|
|
GLenum Type() const { return mType; }
|
2012-12-03 16:13:47 -08:00
|
|
|
protected:
|
2013-09-04 05:14:43 -07:00
|
|
|
GLenum mFormat, mType;
|
2013-10-11 06:16:43 -07:00
|
|
|
WebGLImageDataStatus mImageDataStatus;
|
2012-12-03 16:13:47 -08:00
|
|
|
|
|
|
|
friend class WebGLTexture;
|
|
|
|
};
|
|
|
|
|
2013-10-01 17:30:38 -07:00
|
|
|
private:
|
|
|
|
static size_t FaceForTarget(GLenum target) {
|
|
|
|
// Call this out explicitly:
|
|
|
|
MOZ_ASSERT(target != LOCAL_GL_TEXTURE_CUBE_MAP);
|
|
|
|
MOZ_ASSERT(target == LOCAL_GL_TEXTURE_2D ||
|
|
|
|
(target >= LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X &&
|
|
|
|
target <= LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z));
|
|
|
|
return target == LOCAL_GL_TEXTURE_2D ? 0 : target - LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X;
|
|
|
|
}
|
|
|
|
|
|
|
|
ImageInfo& ImageInfoAtFace(size_t face, GLint level) {
|
|
|
|
MOZ_ASSERT(face < mFacesCount, "wrong face index, must be 0 for TEXTURE_2D and at most 5 for cube maps");
|
|
|
|
|
2012-12-03 16:13:47 -08:00
|
|
|
// no need to check level as a wrong value would be caught by ElementAt().
|
|
|
|
return mImageInfos.ElementAt(level * mFacesCount + face);
|
|
|
|
}
|
|
|
|
|
2013-10-01 17:30:38 -07:00
|
|
|
const ImageInfo& ImageInfoAtFace(size_t face, GLint level) const {
|
|
|
|
return const_cast<const ImageInfo&>(
|
|
|
|
const_cast<WebGLTexture*>(this)->ImageInfoAtFace(face, level)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
ImageInfo& ImageInfoAt(GLenum imageTarget, GLint level) {
|
|
|
|
MOZ_ASSERT(imageTarget);
|
|
|
|
|
|
|
|
size_t face = FaceForTarget(imageTarget);
|
|
|
|
return ImageInfoAtFace(face, level);
|
|
|
|
}
|
|
|
|
|
|
|
|
const ImageInfo& ImageInfoAt(GLenum imageTarget, GLint level) const {
|
|
|
|
return const_cast<WebGLTexture*>(this)->ImageInfoAt(imageTarget, level);
|
2012-12-03 16:13:47 -08:00
|
|
|
}
|
|
|
|
|
2013-10-01 17:30:38 -07:00
|
|
|
bool HasImageInfoAt(GLenum imageTarget, GLint level) const {
|
|
|
|
MOZ_ASSERT(imageTarget);
|
2013-10-11 06:16:43 -07:00
|
|
|
|
2013-10-01 17:30:38 -07:00
|
|
|
size_t face = FaceForTarget(imageTarget);
|
2012-12-03 16:13:47 -08:00
|
|
|
CheckedUint32 checked_index = CheckedUint32(level) * mFacesCount + face;
|
|
|
|
return checked_index.isValid() &&
|
|
|
|
checked_index.value() < mImageInfos.Length() &&
|
2013-10-11 06:16:43 -07:00
|
|
|
ImageInfoAt(imageTarget, level).mImageDataStatus != WebGLImageDataStatus::NoImageData;
|
2012-12-03 16:13:47 -08:00
|
|
|
}
|
|
|
|
|
2013-10-01 17:30:38 -07:00
|
|
|
ImageInfo& ImageInfoBase() {
|
|
|
|
return ImageInfoAtFace(0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
const ImageInfo& ImageInfoBase() const {
|
|
|
|
return ImageInfoAtFace(0, 0);
|
2012-12-03 16:13:47 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
int64_t MemoryUsage() const;
|
|
|
|
|
2013-10-11 06:16:43 -07:00
|
|
|
void SetImageDataStatus(GLenum imageTarget, GLint level, WebGLImageDataStatus newStatus) {
|
|
|
|
MOZ_ASSERT(HasImageInfoAt(imageTarget, level));
|
|
|
|
ImageInfo& imageInfo = ImageInfoAt(imageTarget, level);
|
|
|
|
// there is no way to go from having image data to not having any
|
|
|
|
MOZ_ASSERT(newStatus != WebGLImageDataStatus::NoImageData ||
|
|
|
|
imageInfo.mImageDataStatus == WebGLImageDataStatus::NoImageData);
|
2013-10-11 06:16:43 -07:00
|
|
|
if (imageInfo.mImageDataStatus != newStatus) {
|
|
|
|
SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
|
|
|
|
}
|
2013-10-11 06:16:43 -07:00
|
|
|
imageInfo.mImageDataStatus = newStatus;
|
|
|
|
}
|
|
|
|
|
2012-12-03 16:13:47 -08:00
|
|
|
protected:
|
|
|
|
|
2013-09-04 05:14:43 -07:00
|
|
|
GLenum mTarget;
|
|
|
|
GLenum mMinFilter, mMagFilter, mWrapS, mWrapT;
|
2012-12-03 16:13:47 -08:00
|
|
|
|
|
|
|
size_t mFacesCount, mMaxLevelWithCustomImages;
|
|
|
|
nsTArray<ImageInfo> mImageInfos;
|
|
|
|
|
|
|
|
bool mHaveGeneratedMipmap;
|
2013-10-11 06:16:43 -07:00
|
|
|
WebGLTextureFakeBlackStatus mFakeBlackStatus;
|
2012-12-03 16:13:47 -08:00
|
|
|
|
|
|
|
void EnsureMaxLevelWithCustomImagesAtLeast(size_t aMaxLevelWithCustomImages) {
|
2013-01-15 04:22:03 -08:00
|
|
|
mMaxLevelWithCustomImages = std::max(mMaxLevelWithCustomImages, aMaxLevelWithCustomImages);
|
2012-12-03 16:13:47 -08:00
|
|
|
mImageInfos.EnsureLengthAtLeast((mMaxLevelWithCustomImages + 1) * mFacesCount);
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-10-01 17:30:38 -07:00
|
|
|
bool DoesTexture2DMipmapHaveAllLevelsConsistentlyDefined(GLenum texImageTarget) const;
|
2012-12-03 16:13:47 -08:00
|
|
|
|
|
|
|
public:
|
|
|
|
|
2013-09-04 05:14:43 -07:00
|
|
|
void Bind(GLenum aTarget);
|
2012-12-03 16:13:47 -08:00
|
|
|
|
2013-09-04 05:14:43 -07:00
|
|
|
void SetImageInfo(GLenum aTarget, GLint aLevel,
|
|
|
|
GLsizei aWidth, GLsizei aHeight,
|
2013-10-11 06:16:43 -07:00
|
|
|
GLenum aFormat, GLenum aType, WebGLImageDataStatus aStatus);
|
2012-12-03 16:13:47 -08:00
|
|
|
|
2013-09-04 05:14:43 -07:00
|
|
|
void SetMinFilter(GLenum aMinFilter) {
|
2012-12-03 16:13:47 -08:00
|
|
|
mMinFilter = aMinFilter;
|
2013-10-11 06:16:43 -07:00
|
|
|
SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
|
2012-12-03 16:13:47 -08:00
|
|
|
}
|
2013-09-04 05:14:43 -07:00
|
|
|
void SetMagFilter(GLenum aMagFilter) {
|
2012-12-03 16:13:47 -08:00
|
|
|
mMagFilter = aMagFilter;
|
2013-10-11 06:16:43 -07:00
|
|
|
SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
|
2012-12-03 16:13:47 -08:00
|
|
|
}
|
2013-09-04 05:14:43 -07:00
|
|
|
void SetWrapS(GLenum aWrapS) {
|
2012-12-03 16:13:47 -08:00
|
|
|
mWrapS = aWrapS;
|
2013-10-11 06:16:43 -07:00
|
|
|
SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
|
2012-12-03 16:13:47 -08:00
|
|
|
}
|
2013-09-04 05:14:43 -07:00
|
|
|
void SetWrapT(GLenum aWrapT) {
|
2012-12-03 16:13:47 -08:00
|
|
|
mWrapT = aWrapT;
|
2013-10-11 06:16:43 -07:00
|
|
|
SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
|
2012-12-03 16:13:47 -08:00
|
|
|
}
|
2013-09-04 05:14:43 -07:00
|
|
|
GLenum MinFilter() const { return mMinFilter; }
|
2012-12-03 16:13:47 -08:00
|
|
|
|
|
|
|
bool DoesMinFilterRequireMipmap() const {
|
|
|
|
return !(mMinFilter == LOCAL_GL_NEAREST || mMinFilter == LOCAL_GL_LINEAR);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetGeneratedMipmap();
|
|
|
|
|
|
|
|
void SetCustomMipmap();
|
|
|
|
|
|
|
|
bool IsFirstImagePowerOfTwo() const {
|
2013-10-01 17:30:38 -07:00
|
|
|
return ImageInfoBase().IsPowerOfTwo();
|
2012-12-03 16:13:47 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool AreAllLevel0ImageInfosEqual() const;
|
|
|
|
|
|
|
|
bool IsMipmapTexture2DComplete() const;
|
|
|
|
|
|
|
|
bool IsCubeComplete() const;
|
|
|
|
|
|
|
|
bool IsMipmapCubeComplete() const;
|
|
|
|
|
2013-10-11 06:16:43 -07:00
|
|
|
void SetFakeBlackStatus(WebGLTextureFakeBlackStatus x) {
|
|
|
|
mFakeBlackStatus = x;
|
|
|
|
mContext->SetFakeBlackStatus(WebGLContextFakeBlackStatus::Unknown);
|
|
|
|
}
|
|
|
|
// Returns the current fake-black-status, except if it was Unknown,
|
|
|
|
// in which case this function resolves it first, so it never returns Unknown.
|
|
|
|
WebGLTextureFakeBlackStatus ResolvedFakeBlackStatus();
|
2012-12-03 16:13:47 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace mozilla
|
|
|
|
|
|
|
|
#endif
|