|
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/. */ |
|
5 |
|
6 #ifndef WEBGLTEXTURE_H_ |
|
7 #define WEBGLTEXTURE_H_ |
|
8 |
|
9 #include "WebGLObjectModel.h" |
|
10 #include "WebGLFramebufferAttachable.h" |
|
11 |
|
12 #include "nsWrapperCache.h" |
|
13 |
|
14 #include "mozilla/LinkedList.h" |
|
15 #include <algorithm> |
|
16 |
|
17 namespace mozilla { |
|
18 |
|
19 // Zero is not an integer power of two. |
|
20 inline bool is_pot_assuming_nonnegative(GLsizei x) |
|
21 { |
|
22 return x && (x & (x-1)) == 0; |
|
23 } |
|
24 |
|
25 // NOTE: When this class is switched to new DOM bindings, update the (then-slow) |
|
26 // WrapObject calls in GetParameter and GetFramebufferAttachmentParameter. |
|
27 class WebGLTexture MOZ_FINAL |
|
28 : public nsWrapperCache |
|
29 , public WebGLRefCountedObject<WebGLTexture> |
|
30 , public LinkedListElement<WebGLTexture> |
|
31 , public WebGLContextBoundObject |
|
32 , public WebGLFramebufferAttachable |
|
33 { |
|
34 public: |
|
35 WebGLTexture(WebGLContext *context); |
|
36 |
|
37 ~WebGLTexture() { |
|
38 DeleteOnce(); |
|
39 } |
|
40 |
|
41 void Delete(); |
|
42 |
|
43 bool HasEverBeenBound() const { return mHasEverBeenBound; } |
|
44 void SetHasEverBeenBound(bool x) { mHasEverBeenBound = x; } |
|
45 GLuint GLName() const { return mGLName; } |
|
46 GLenum Target() const { return mTarget; } |
|
47 |
|
48 WebGLContext *GetParentObject() const { |
|
49 return Context(); |
|
50 } |
|
51 |
|
52 virtual JSObject* WrapObject(JSContext *cx) MOZ_OVERRIDE; |
|
53 |
|
54 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLTexture) |
|
55 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLTexture) |
|
56 |
|
57 protected: |
|
58 |
|
59 friend class WebGLContext; |
|
60 friend class WebGLFramebuffer; |
|
61 |
|
62 bool mHasEverBeenBound; |
|
63 GLuint mGLName; |
|
64 |
|
65 // we store information about the various images that are part of |
|
66 // this texture (cubemap faces, mipmap levels) |
|
67 |
|
68 public: |
|
69 |
|
70 class ImageInfo |
|
71 : public WebGLRectangleObject |
|
72 { |
|
73 public: |
|
74 ImageInfo() |
|
75 : mWebGLFormat(LOCAL_GL_NONE) |
|
76 , mWebGLType(LOCAL_GL_NONE) |
|
77 , mImageDataStatus(WebGLImageDataStatus::NoImageData) |
|
78 {} |
|
79 |
|
80 ImageInfo(GLsizei width, |
|
81 GLsizei height, |
|
82 GLenum webGLFormat, |
|
83 GLenum webGLType, |
|
84 WebGLImageDataStatus status) |
|
85 : WebGLRectangleObject(width, height) |
|
86 , mWebGLFormat(webGLFormat) |
|
87 , mWebGLType(webGLType) |
|
88 , mImageDataStatus(status) |
|
89 { |
|
90 // shouldn't use this constructor to construct a null ImageInfo |
|
91 MOZ_ASSERT(status != WebGLImageDataStatus::NoImageData); |
|
92 } |
|
93 |
|
94 bool operator==(const ImageInfo& a) const { |
|
95 return mImageDataStatus == a.mImageDataStatus && |
|
96 mWidth == a.mWidth && |
|
97 mHeight == a.mHeight && |
|
98 mWebGLFormat == a.mWebGLFormat && |
|
99 mWebGLType == a.mWebGLType; |
|
100 } |
|
101 bool operator!=(const ImageInfo& a) const { |
|
102 return !(*this == a); |
|
103 } |
|
104 bool IsSquare() const { |
|
105 return mWidth == mHeight; |
|
106 } |
|
107 bool IsPositive() const { |
|
108 return mWidth > 0 && mHeight > 0; |
|
109 } |
|
110 bool IsPowerOfTwo() const { |
|
111 return is_pot_assuming_nonnegative(mWidth) && |
|
112 is_pot_assuming_nonnegative(mHeight); // negative sizes should never happen (caught in texImage2D...) |
|
113 } |
|
114 bool HasUninitializedImageData() const { |
|
115 return mImageDataStatus == WebGLImageDataStatus::UninitializedImageData; |
|
116 } |
|
117 int64_t MemoryUsage() const; |
|
118 /*! This is the format passed from JS to WebGL. |
|
119 * It can be converted to a value to be passed to driver with |
|
120 * DriverFormatsFromFormatAndType(). |
|
121 */ |
|
122 GLenum WebGLFormat() const { return mWebGLFormat; } |
|
123 /*! This is the type passed from JS to WebGL. |
|
124 * It can be converted to a value to be passed to driver with |
|
125 * DriverTypeFromType(). |
|
126 */ |
|
127 GLenum WebGLType() const { return mWebGLType; } |
|
128 |
|
129 protected: |
|
130 GLenum mWebGLFormat; //!< This is the WebGL/GLES format |
|
131 GLenum mWebGLType; //!< This is the WebGL/GLES type |
|
132 WebGLImageDataStatus mImageDataStatus; |
|
133 |
|
134 friend class WebGLTexture; |
|
135 }; |
|
136 |
|
137 private: |
|
138 static size_t FaceForTarget(GLenum target) { |
|
139 // Call this out explicitly: |
|
140 MOZ_ASSERT(target != LOCAL_GL_TEXTURE_CUBE_MAP); |
|
141 MOZ_ASSERT(target == LOCAL_GL_TEXTURE_2D || |
|
142 (target >= LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X && |
|
143 target <= LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)); |
|
144 return target == LOCAL_GL_TEXTURE_2D ? 0 : target - LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X; |
|
145 } |
|
146 |
|
147 ImageInfo& ImageInfoAtFace(size_t face, GLint level) { |
|
148 MOZ_ASSERT(face < mFacesCount, "wrong face index, must be 0 for TEXTURE_2D and at most 5 for cube maps"); |
|
149 |
|
150 // no need to check level as a wrong value would be caught by ElementAt(). |
|
151 return mImageInfos.ElementAt(level * mFacesCount + face); |
|
152 } |
|
153 |
|
154 const ImageInfo& ImageInfoAtFace(size_t face, GLint level) const { |
|
155 return const_cast<const ImageInfo&>( |
|
156 const_cast<WebGLTexture*>(this)->ImageInfoAtFace(face, level) |
|
157 ); |
|
158 } |
|
159 |
|
160 public: |
|
161 ImageInfo& ImageInfoAt(GLenum imageTarget, GLint level) { |
|
162 MOZ_ASSERT(imageTarget); |
|
163 |
|
164 size_t face = FaceForTarget(imageTarget); |
|
165 return ImageInfoAtFace(face, level); |
|
166 } |
|
167 |
|
168 const ImageInfo& ImageInfoAt(GLenum imageTarget, GLint level) const { |
|
169 return const_cast<WebGLTexture*>(this)->ImageInfoAt(imageTarget, level); |
|
170 } |
|
171 |
|
172 bool HasImageInfoAt(GLenum imageTarget, GLint level) const { |
|
173 MOZ_ASSERT(imageTarget); |
|
174 |
|
175 size_t face = FaceForTarget(imageTarget); |
|
176 CheckedUint32 checked_index = CheckedUint32(level) * mFacesCount + face; |
|
177 return checked_index.isValid() && |
|
178 checked_index.value() < mImageInfos.Length() && |
|
179 ImageInfoAt(imageTarget, level).mImageDataStatus != WebGLImageDataStatus::NoImageData; |
|
180 } |
|
181 |
|
182 ImageInfo& ImageInfoBase() { |
|
183 return ImageInfoAtFace(0, 0); |
|
184 } |
|
185 |
|
186 const ImageInfo& ImageInfoBase() const { |
|
187 return ImageInfoAtFace(0, 0); |
|
188 } |
|
189 |
|
190 int64_t MemoryUsage() const; |
|
191 |
|
192 void SetImageDataStatus(GLenum imageTarget, GLint level, WebGLImageDataStatus newStatus) { |
|
193 MOZ_ASSERT(HasImageInfoAt(imageTarget, level)); |
|
194 ImageInfo& imageInfo = ImageInfoAt(imageTarget, level); |
|
195 // there is no way to go from having image data to not having any |
|
196 MOZ_ASSERT(newStatus != WebGLImageDataStatus::NoImageData || |
|
197 imageInfo.mImageDataStatus == WebGLImageDataStatus::NoImageData); |
|
198 if (imageInfo.mImageDataStatus != newStatus) { |
|
199 SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown); |
|
200 } |
|
201 imageInfo.mImageDataStatus = newStatus; |
|
202 } |
|
203 |
|
204 void DoDeferredImageInitialization(GLenum imageTarget, GLint level); |
|
205 |
|
206 protected: |
|
207 |
|
208 GLenum mTarget; |
|
209 GLenum mMinFilter, mMagFilter, mWrapS, mWrapT; |
|
210 |
|
211 size_t mFacesCount, mMaxLevelWithCustomImages; |
|
212 nsTArray<ImageInfo> mImageInfos; |
|
213 |
|
214 bool mHaveGeneratedMipmap; |
|
215 WebGLTextureFakeBlackStatus mFakeBlackStatus; |
|
216 |
|
217 void EnsureMaxLevelWithCustomImagesAtLeast(size_t aMaxLevelWithCustomImages) { |
|
218 mMaxLevelWithCustomImages = std::max(mMaxLevelWithCustomImages, aMaxLevelWithCustomImages); |
|
219 mImageInfos.EnsureLengthAtLeast((mMaxLevelWithCustomImages + 1) * mFacesCount); |
|
220 } |
|
221 |
|
222 bool CheckFloatTextureFilterParams() const { |
|
223 // Without OES_texture_float_linear, only NEAREST and NEAREST_MIMPAMP_NEAREST are supported |
|
224 return (mMagFilter == LOCAL_GL_NEAREST) && |
|
225 (mMinFilter == LOCAL_GL_NEAREST || mMinFilter == LOCAL_GL_NEAREST_MIPMAP_NEAREST); |
|
226 } |
|
227 |
|
228 bool AreBothWrapModesClampToEdge() const { |
|
229 return mWrapS == LOCAL_GL_CLAMP_TO_EDGE && mWrapT == LOCAL_GL_CLAMP_TO_EDGE; |
|
230 } |
|
231 |
|
232 bool DoesTexture2DMipmapHaveAllLevelsConsistentlyDefined(GLenum texImageTarget) const; |
|
233 |
|
234 public: |
|
235 |
|
236 void Bind(GLenum aTarget); |
|
237 |
|
238 void SetImageInfo(GLenum aTarget, GLint aLevel, |
|
239 GLsizei aWidth, GLsizei aHeight, |
|
240 GLenum aFormat, GLenum aType, WebGLImageDataStatus aStatus); |
|
241 |
|
242 void SetMinFilter(GLenum aMinFilter) { |
|
243 mMinFilter = aMinFilter; |
|
244 SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown); |
|
245 } |
|
246 void SetMagFilter(GLenum aMagFilter) { |
|
247 mMagFilter = aMagFilter; |
|
248 SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown); |
|
249 } |
|
250 void SetWrapS(GLenum aWrapS) { |
|
251 mWrapS = aWrapS; |
|
252 SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown); |
|
253 } |
|
254 void SetWrapT(GLenum aWrapT) { |
|
255 mWrapT = aWrapT; |
|
256 SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown); |
|
257 } |
|
258 GLenum MinFilter() const { return mMinFilter; } |
|
259 |
|
260 bool DoesMinFilterRequireMipmap() const { |
|
261 return !(mMinFilter == LOCAL_GL_NEAREST || mMinFilter == LOCAL_GL_LINEAR); |
|
262 } |
|
263 |
|
264 void SetGeneratedMipmap(); |
|
265 |
|
266 void SetCustomMipmap(); |
|
267 |
|
268 bool IsFirstImagePowerOfTwo() const { |
|
269 return ImageInfoBase().IsPowerOfTwo(); |
|
270 } |
|
271 |
|
272 bool AreAllLevel0ImageInfosEqual() const; |
|
273 |
|
274 bool IsMipmapTexture2DComplete() const; |
|
275 |
|
276 bool IsCubeComplete() const; |
|
277 |
|
278 bool IsMipmapCubeComplete() const; |
|
279 |
|
280 void SetFakeBlackStatus(WebGLTextureFakeBlackStatus x) { |
|
281 mFakeBlackStatus = x; |
|
282 mContext->SetFakeBlackStatus(WebGLContextFakeBlackStatus::Unknown); |
|
283 } |
|
284 // Returns the current fake-black-status, except if it was Unknown, |
|
285 // in which case this function resolves it first, so it never returns Unknown. |
|
286 WebGLTextureFakeBlackStatus ResolvedFakeBlackStatus(); |
|
287 }; |
|
288 |
|
289 } // namespace mozilla |
|
290 |
|
291 #endif |