1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef WEBGL_TEXTURE_H_
7 #define WEBGL_TEXTURE_H_
10 #include "mozilla/Assertions.h"
11 #include "mozilla/CheckedInt.h"
12 #include "mozilla/LinkedList.h"
13 #include "nsAlgorithm.h"
14 #include "nsWrapperCache.h"
15 #include "WebGLBindableName.h"
16 #include "WebGLFramebufferAttachable.h"
17 #include "WebGLObjectModel.h"
18 #include "WebGLStrongTypes.h"
22 // Zero is not an integer power of two.
24 IsPOTAssumingNonnegative(GLsizei x
)
27 return x
&& (x
& (x
-1)) == 0;
30 // NOTE: When this class is switched to new DOM bindings, update the (then-slow)
31 // WrapObject calls in GetParameter and GetFramebufferAttachmentParameter.
32 class WebGLTexture MOZ_FINAL
33 : public nsWrapperCache
34 , public WebGLBindableName
<TexTarget
>
35 , public WebGLRefCountedObject
<WebGLTexture
>
36 , public LinkedListElement
<WebGLTexture
>
37 , public WebGLContextBoundObject
38 , public WebGLFramebufferAttachable
41 explicit WebGLTexture(WebGLContext
* webgl
, GLuint tex
);
45 WebGLContext
* GetParentObject() const {
49 virtual JSObject
* WrapObject(JSContext
* cx
) MOZ_OVERRIDE
;
51 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLTexture
)
52 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLTexture
)
59 friend class WebGLContext
;
60 friend class WebGLFramebuffer
;
62 // We store information about the various images that are part of this
63 // texture. (cubemap faces, mipmap levels)
67 : public WebGLRectangleObject
71 : mEffectiveInternalFormat(LOCAL_GL_NONE
)
73 , mImageDataStatus(WebGLImageDataStatus::NoImageData
)
76 ImageInfo(GLsizei width
, GLsizei height
, GLsizei depth
,
77 TexInternalFormat effectiveInternalFormat
,
78 WebGLImageDataStatus status
)
79 : WebGLRectangleObject(width
, height
)
80 , mEffectiveInternalFormat(effectiveInternalFormat
)
82 , mImageDataStatus(status
)
84 // shouldn't use this constructor to construct a null ImageInfo
85 MOZ_ASSERT(status
!= WebGLImageDataStatus::NoImageData
);
88 bool operator==(const ImageInfo
& a
) const {
89 return mImageDataStatus
== a
.mImageDataStatus
&&
91 mHeight
== a
.mHeight
&&
93 mEffectiveInternalFormat
== a
.mEffectiveInternalFormat
;
95 bool operator!=(const ImageInfo
& a
) const {
98 bool IsSquare() const {
99 return mWidth
== mHeight
;
101 bool IsPositive() const {
102 return mWidth
> 0 && mHeight
> 0 && mDepth
> 0;
104 bool IsPowerOfTwo() const {
105 MOZ_ASSERT(mWidth
>= 0);
106 MOZ_ASSERT(mHeight
>= 0);
107 return IsPOTAssumingNonnegative(mWidth
) &&
108 IsPOTAssumingNonnegative(mHeight
);
110 bool HasUninitializedImageData() const {
111 return mImageDataStatus
== WebGLImageDataStatus::UninitializedImageData
;
113 size_t MemoryUsage() const;
115 TexInternalFormat
EffectiveInternalFormat() const {
116 return mEffectiveInternalFormat
;
118 GLsizei
Depth() const { return mDepth
; }
121 // This is the "effective internal format" of the texture, an official
122 // OpenGL spec concept, see OpenGL ES 3.0.3 spec, section 3.8.3, page
124 TexInternalFormat mEffectiveInternalFormat
;
126 /* Used only for 3D textures.
127 * Note that mWidth and mHeight are inherited from WebGLRectangleObject.
128 * It's a pity to store a useless mDepth on non-3D texture images, but
129 * the size of GLsizei is negligible compared to the typical size of a texture image.
133 WebGLImageDataStatus mImageDataStatus
;
135 friend class WebGLTexture
;
139 static size_t FaceForTarget(TexImageTarget texImageTarget
) {
140 if (texImageTarget
== LOCAL_GL_TEXTURE_2D
||
141 texImageTarget
== LOCAL_GL_TEXTURE_3D
)
145 return texImageTarget
.get() - LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X
;
148 ImageInfo
& ImageInfoAtFace(size_t face
, GLint level
) {
149 MOZ_ASSERT(face
< mFacesCount
,
150 "Wrong face index, must be 0 for TEXTURE_2D or TEXTURE_3D,"
151 " and at most 5 for cube maps.");
153 // No need to check level as a wrong value would be caught by
155 return mImageInfos
.ElementAt(level
* mFacesCount
+ face
);
158 const ImageInfo
& ImageInfoAtFace(size_t face
, GLint level
) const {
159 return const_cast<const ImageInfo
&>(
160 const_cast<WebGLTexture
*>(this)->ImageInfoAtFace(face
, level
)
165 ImageInfo
& ImageInfoAt(TexImageTarget imageTarget
, GLint level
) {
166 size_t face
= FaceForTarget(imageTarget
);
167 return ImageInfoAtFace(face
, level
);
170 const ImageInfo
& ImageInfoAt(TexImageTarget imageTarget
, GLint level
) const
172 return const_cast<WebGLTexture
*>(this)->ImageInfoAt(imageTarget
, level
);
175 bool HasImageInfoAt(TexImageTarget imageTarget
, GLint level
) const {
176 size_t face
= FaceForTarget(imageTarget
);
177 CheckedUint32 checked_index
= CheckedUint32(level
) * mFacesCount
+ face
;
178 return checked_index
.isValid() &&
179 checked_index
.value() < mImageInfos
.Length() &&
180 ImageInfoAt(imageTarget
, level
).mImageDataStatus
!= WebGLImageDataStatus::NoImageData
;
183 ImageInfo
& ImageInfoBase() {
184 return ImageInfoAtFace(0, 0);
187 const ImageInfo
& ImageInfoBase() const {
188 return ImageInfoAtFace(0, 0);
191 size_t MemoryUsage() const;
193 void SetImageDataStatus(TexImageTarget imageTarget
, GLint level
,
194 WebGLImageDataStatus newStatus
)
196 MOZ_ASSERT(HasImageInfoAt(imageTarget
, level
));
197 ImageInfo
& imageInfo
= ImageInfoAt(imageTarget
, level
);
198 // There is no way to go from having image data to not having any.
199 MOZ_ASSERT(newStatus
!= WebGLImageDataStatus::NoImageData
||
200 imageInfo
.mImageDataStatus
== WebGLImageDataStatus::NoImageData
);
202 if (imageInfo
.mImageDataStatus
!= newStatus
)
203 SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown
);
205 imageInfo
.mImageDataStatus
= newStatus
;
208 void EnsureNoUninitializedImageData(TexImageTarget imageTarget
, GLint level
);
211 TexMinFilter mMinFilter
;
212 TexMagFilter mMagFilter
;
213 TexWrap mWrapS
, mWrapT
;
215 size_t mFacesCount
, mMaxLevelWithCustomImages
;
216 nsTArray
<ImageInfo
> mImageInfos
;
218 bool mHaveGeneratedMipmap
; // Set by generateMipmap
219 bool mImmutable
; // Set by texStorage*
221 size_t mBaseMipmapLevel
; // Set by texParameter (defaults to 0)
222 size_t mMaxMipmapLevel
; // Set by texParameter (defaults to 1000)
224 WebGLTextureFakeBlackStatus mFakeBlackStatus
;
226 void EnsureMaxLevelWithCustomImagesAtLeast(size_t maxLevelWithCustomImages
) {
227 mMaxLevelWithCustomImages
= std::max(mMaxLevelWithCustomImages
,
228 maxLevelWithCustomImages
);
229 mImageInfos
.EnsureLengthAtLeast((mMaxLevelWithCustomImages
+ 1) * mFacesCount
);
232 bool CheckFloatTextureFilterParams() const {
233 // Without OES_texture_float_linear, only NEAREST and
234 // NEAREST_MIMPAMP_NEAREST are supported.
235 return mMagFilter
== LOCAL_GL_NEAREST
&&
236 (mMinFilter
== LOCAL_GL_NEAREST
||
237 mMinFilter
== LOCAL_GL_NEAREST_MIPMAP_NEAREST
);
240 bool AreBothWrapModesClampToEdge() const {
241 return mWrapS
== LOCAL_GL_CLAMP_TO_EDGE
&&
242 mWrapT
== LOCAL_GL_CLAMP_TO_EDGE
;
245 bool DoesMipmapHaveAllLevelsConsistentlyDefined(TexImageTarget texImageTarget
) const;
248 void Bind(TexTarget texTarget
);
250 void SetImageInfo(TexImageTarget target
, GLint level
, GLsizei width
,
251 GLsizei height
, GLsizei depth
, TexInternalFormat format
,
252 WebGLImageDataStatus status
);
254 void SetMinFilter(TexMinFilter minFilter
) {
255 mMinFilter
= minFilter
;
256 SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown
);
258 void SetMagFilter(TexMagFilter magFilter
) {
259 mMagFilter
= magFilter
;
260 SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown
);
262 void SetWrapS(TexWrap wrapS
) {
264 SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown
);
266 void SetWrapT(TexWrap wrapT
) {
268 SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown
);
270 TexMinFilter
MinFilter() const { return mMinFilter
; }
272 bool DoesMinFilterRequireMipmap() const {
273 return !(mMinFilter
== LOCAL_GL_NEAREST
||
274 mMinFilter
== LOCAL_GL_LINEAR
);
277 void SetGeneratedMipmap();
279 void SetCustomMipmap();
281 bool IsFirstImagePowerOfTwo() const {
282 return ImageInfoBase().IsPowerOfTwo();
285 bool AreAllLevel0ImageInfosEqual() const;
287 bool IsMipmapComplete() const;
289 bool IsCubeComplete() const;
291 bool IsMipmapCubeComplete() const;
293 void SetFakeBlackStatus(WebGLTextureFakeBlackStatus x
);
295 bool IsImmutable() const { return mImmutable
; }
296 void SetImmutable() { mImmutable
= true; }
298 void SetBaseMipmapLevel(size_t level
) { mBaseMipmapLevel
= level
; }
299 void SetMaxMipmapLevel(size_t level
) { mMaxMipmapLevel
= level
; }
301 // Clamping (from ES 3.0.4, section 3.8 - Texturing). When not immutable,
302 // the ranges must be guarded.
303 size_t EffectiveBaseMipmapLevel() const {
305 return std::min(mBaseMipmapLevel
, mMaxLevelWithCustomImages
);
306 return mBaseMipmapLevel
;
308 size_t EffectiveMaxMipmapLevel() const {
310 return mozilla::clamped(mMaxMipmapLevel
, EffectiveBaseMipmapLevel(),
311 mMaxLevelWithCustomImages
);
313 return std::min(mMaxMipmapLevel
, mMaxLevelWithCustomImages
);
315 bool IsMipmapRangeValid() const;
317 size_t MaxLevelWithCustomImages() const { return mMaxLevelWithCustomImages
; }
319 // Returns the current fake-black-status, except if it was Unknown,
320 // in which case this function resolves it first, so it never returns Unknown.
321 WebGLTextureFakeBlackStatus
ResolvedFakeBlackStatus();
324 inline TexImageTarget
325 TexImageTargetForTargetAndFace(TexTarget target
, size_t face
)
327 switch (target
.get()) {
328 case LOCAL_GL_TEXTURE_2D
:
329 case LOCAL_GL_TEXTURE_3D
:
330 MOZ_ASSERT(face
== 0);
332 case LOCAL_GL_TEXTURE_CUBE_MAP
:
333 MOZ_ASSERT(face
< 6);
334 return LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X
+ face
;
340 } // namespace mozilla
342 #endif // WEBGL_TEXTURE_H_