1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
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 WEBGL_TEXTURE_H_
7 #define WEBGL_TEXTURE_H_
8 
9 #include <algorithm>
10 #include <map>
11 #include <set>
12 #include <vector>
13 
14 #include "mozilla/Assertions.h"
15 #include "mozilla/Casting.h"
16 #include "mozilla/CheckedInt.h"
17 #include "mozilla/dom/TypedArray.h"
18 
19 #include "CacheInvalidator.h"
20 #include "WebGLObjectModel.h"
21 #include "WebGLStrongTypes.h"
22 #include "WebGLTypes.h"
23 
24 namespace mozilla {
25 class ErrorResult;
26 class WebGLContext;
27 class WebGLFramebuffer;
28 class WebGLSampler;
29 struct FloatOrInt;
30 struct TexImageSource;
31 
32 namespace dom {
33 class Element;
34 class HTMLVideoElement;
35 class ImageData;
36 class ArrayBufferViewOrSharedArrayBufferView;
37 }  // namespace dom
38 
39 namespace layers {
40 class Image;
41 }  // namespace layers
42 
43 namespace webgl {
44 struct DriverUnpackInfo;
45 struct FormatUsageInfo;
46 struct PackingInfo;
47 class TexUnpackBlob;
48 }  // namespace webgl
49 
50 bool DoesTargetMatchDimensions(WebGLContext* webgl, TexImageTarget target,
51                                uint8_t dims);
52 
53 namespace webgl {
54 
55 struct SamplingState final {
56   // Only store that which changes validation.
57   TexMinFilter minFilter = LOCAL_GL_NEAREST_MIPMAP_LINEAR;
58   TexMagFilter magFilter = LOCAL_GL_LINEAR;
59   TexWrap wrapS = LOCAL_GL_REPEAT;
60   TexWrap wrapT = LOCAL_GL_REPEAT;
61   // TexWrap wrapR = LOCAL_GL_REPEAT;
62   // GLfloat minLod = -1000;
63   // GLfloat maxLod = 1000;
64   TexCompareMode compareMode = LOCAL_GL_NONE;
65   // TexCompareFunc compareFunc = LOCAL_GL_LEQUAL;
66 };
67 
68 struct ImageInfo final {
69   static const ImageInfo kUndefined;
70 
71   const webgl::FormatUsageInfo* mFormat = nullptr;
72   uint32_t mWidth = 0;
73   uint32_t mHeight = 0;
74   uint32_t mDepth = 0;
75   mutable Maybe<std::vector<bool>> mUninitializedSlices;
76   uint8_t mSamples = 0;
77 
78   // -
79 
80   size_t MemoryUsage() const;
81 
IsDefinedfinal82   bool IsDefined() const {
83     if (!mFormat) {
84       MOZ_ASSERT(!mWidth && !mHeight && !mDepth);
85       return false;
86     }
87 
88     return true;
89   }
90 
91   Maybe<ImageInfo> NextMip(GLenum target) const;
92 };
93 
94 }  // namespace webgl
95 
96 class WebGLTexture final : public WebGLContextBoundObject,
97                            public CacheInvalidator {
98   // Friends
99   friend class WebGLContext;
100   friend class WebGLFramebuffer;
101 
102   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(WebGLTexture, override)
103 
104   ////////////////////////////////////
105   // Members
106  public:
107   const GLuint mGLName;
108 
109  protected:
110   TexTarget mTarget;
111 
112   static const uint8_t kMaxFaceCount = 6;
113   uint8_t mFaceCount;  // 6 for cube maps, 1 otherwise.
114 
115   bool mImmutable;  // Set by texStorage*
116   uint8_t mImmutableLevelCount;
117 
118   uint32_t mBaseMipmapLevel;  // Set by texParameter (defaults to 0)
119   uint32_t mMaxMipmapLevel;   // Set by texParameter (defaults to 1000)
120   // You almost certainly don't want to query mMaxMipmapLevel.
121   // You almost certainly want MaxEffectiveMipmapLevel().
122 
123   webgl::SamplingState mSamplingState;
124 
125   mutable const GLint* mCurSwizzle =
126       nullptr;  // nullptr means 'default swizzle'.
127 
128   // -
129 
130   struct CompletenessInfo final {
131     uint8_t levels = 0;
132     bool powerOfTwo = false;
133     bool mipmapComplete = false;
134     const webgl::FormatUsageInfo* usage = nullptr;
135     const char* incompleteReason = nullptr;
136   };
137 
138   mutable CacheWeakMap<const WebGLSampler*, webgl::SampleableInfo>
139       mSamplingCache;
140 
141  public:
142   Maybe<const CompletenessInfo> CalcCompletenessInfo(
143       bool ensureInit, bool skipMips = false) const;
144   Maybe<const webgl::SampleableInfo> CalcSampleableInfo(
145       const WebGLSampler*) const;
146 
147   const webgl::SampleableInfo* GetSampleableInfo(const WebGLSampler*) const;
148 
149   // -
150 
Immutable()151   const auto& Immutable() const { return mImmutable; }
BaseMipmapLevel()152   const auto& BaseMipmapLevel() const { return mBaseMipmapLevel; }
FaceCount()153   const auto& FaceCount() const { return mFaceCount; }
154 
155   // We can just max this out to 31, which is the number of unsigned bits in
156   // GLsizei.
157   static const uint8_t kMaxLevelCount = 31;
158 
159   // We store information about the various images that are part of this
160   // texture. (cubemap faces, mipmap levels)
161   webgl::ImageInfo mImageInfoArr[kMaxLevelCount * kMaxFaceCount];
162 
163   ////////////////////////////////////
164 
165   WebGLTexture(WebGLContext* webgl, GLuint tex);
166 
Target()167   TexTarget Target() const { return mTarget; }
168 
169  protected:
170   ~WebGLTexture() override;
171 
172  public:
173   ////////////////////////////////////
174   // GL calls
175   bool BindTexture(TexTarget texTarget);
176   void GenerateMipmap();
177   Maybe<double> GetTexParameter(GLenum pname) const;
178   void TexParameter(TexTarget texTarget, GLenum pname, const FloatOrInt& param);
179 
180   ////////////////////////////////////
181   // WebGLTextureUpload.cpp
182 
183  protected:
184   void TexOrSubImageBlob(bool isSubImage, TexImageTarget target, GLint level,
185                          GLenum internalFormat, GLint xOffset, GLint yOffset,
186                          GLint zOffset, const webgl::PackingInfo& pi,
187                          const webgl::TexUnpackBlob* blob);
188 
189   bool ValidateTexImageSpecification(TexImageTarget target, uint32_t level,
190                                      const uvec3& size,
191                                      webgl::ImageInfo** const out_imageInfo);
192   bool ValidateTexImageSelection(TexImageTarget target, uint32_t level,
193                                  const uvec3& offset, const uvec3& size,
194                                  webgl::ImageInfo** const out_imageInfo);
195 
196   bool ValidateUnpack(const webgl::TexUnpackBlob* blob, bool isFunc3D,
197                       const webgl::PackingInfo& srcPI) const;
198 
199  public:
200   void TexStorage(TexTarget target, uint32_t levels, GLenum sizedFormat,
201                   const uvec3& size);
202 
203   // TexSubImage iff `!respecFormat`
204   void TexImage(GLenum imageTarget, uint32_t level, GLenum respecFormat,
205                 const uvec3& offset, const uvec3& size,
206                 const webgl::PackingInfo& pi, const TexImageSource& src,
207                 const dom::HTMLCanvasElement& canvas);
208 
209   // CompressedTexSubImage iff `sub`
210   void CompressedTexImage(bool sub, GLenum imageTarget, uint32_t level,
211                           GLenum formatEnum, const uvec3& offset,
212                           const uvec3& size, const Range<const uint8_t>& src,
213                           const uint32_t pboImageSize,
214                           const Maybe<uint64_t>& pboOffset);
215 
216   // CopyTexSubImage iff `!respecFormat`
217   void CopyTexImage(GLenum imageTarget, uint32_t level, GLenum respecFormat,
218                     const uvec3& dstOffset, const ivec2& srcOffset,
219                     const uvec2& size2);
220 
221   ////////////////////////////////////
222 
223  protected:
224   void ClampLevelBaseAndMax();
225   void RefreshSwizzle() const;
226 
227  public:
228   uint32_t EffectiveMaxLevel() const;  // GLES 3.0.5 p158: `q`
229 
230  protected:
FaceForTarget(TexImageTarget texImageTarget)231   static uint8_t FaceForTarget(TexImageTarget texImageTarget) {
232     GLenum rawTexImageTarget = texImageTarget.get();
233     switch (rawTexImageTarget) {
234       case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
235       case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
236       case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
237       case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
238       case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
239       case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
240         return AutoAssertCast(rawTexImageTarget -
241                               LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X);
242 
243       default:
244         return 0;
245     }
246   }
247 
248  public:
ImageInfoAtFace(uint8_t face,uint32_t level)249   auto& ImageInfoAtFace(uint8_t face, uint32_t level) {
250     MOZ_ASSERT(face < mFaceCount);
251     MOZ_ASSERT(level < kMaxLevelCount);
252     size_t pos = (level * mFaceCount) + face;
253     return mImageInfoArr[pos];
254   }
255 
ImageInfoAtFace(uint8_t face,uint32_t level)256   const auto& ImageInfoAtFace(uint8_t face, uint32_t level) const {
257     return const_cast<WebGLTexture*>(this)->ImageInfoAtFace(face, level);
258   }
259 
ImageInfoAt(TexImageTarget texImageTarget,GLint level)260   auto& ImageInfoAt(TexImageTarget texImageTarget, GLint level) {
261     const auto& face = FaceForTarget(texImageTarget);
262     return ImageInfoAtFace(face, level);
263   }
264 
ImageInfoAt(TexImageTarget texImageTarget,GLint level)265   const auto& ImageInfoAt(TexImageTarget texImageTarget, GLint level) const {
266     return const_cast<WebGLTexture*>(this)->ImageInfoAt(texImageTarget, level);
267   }
268 
BaseImageInfo()269   const auto& BaseImageInfo() const {
270     if (mBaseMipmapLevel >= kMaxLevelCount) return webgl::ImageInfo::kUndefined;
271 
272     return ImageInfoAtFace(0, mBaseMipmapLevel);
273   }
274 
275   size_t MemoryUsage() const;
276 
277   bool EnsureImageDataInitialized(TexImageTarget target, uint32_t level);
278   void PopulateMipChain(uint32_t maxLevel);
279   bool IsMipAndCubeComplete(uint32_t maxLevel, bool ensureInit,
280                             bool* out_initFailed) const;
281   void Truncate();
282 
IsCubeMap()283   bool IsCubeMap() const { return (mTarget == LOCAL_GL_TEXTURE_CUBE_MAP); }
284 };
285 
TexImageTargetForTargetAndFace(TexTarget target,uint8_t face)286 inline TexImageTarget TexImageTargetForTargetAndFace(TexTarget target,
287                                                      uint8_t face) {
288   switch (target.get()) {
289     case LOCAL_GL_TEXTURE_2D:
290     case LOCAL_GL_TEXTURE_3D:
291       MOZ_ASSERT(face == 0);
292       return target.get();
293     case LOCAL_GL_TEXTURE_CUBE_MAP:
294       MOZ_ASSERT(face < 6);
295       return LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
296     default:
297       MOZ_CRASH("GFX: TexImageTargetForTargetAndFace");
298   }
299 }
300 
301 already_AddRefed<mozilla::layers::Image> ImageFromVideo(
302     dom::HTMLVideoElement* elem);
303 
304 bool IsTarget3D(TexImageTarget target);
305 
306 GLenum DoTexImage(gl::GLContext* gl, TexImageTarget target, GLint level,
307                   const webgl::DriverUnpackInfo* dui, GLsizei width,
308                   GLsizei height, GLsizei depth, const void* data);
309 GLenum DoTexSubImage(gl::GLContext* gl, TexImageTarget target, GLint level,
310                      GLint xOffset, GLint yOffset, GLint zOffset, GLsizei width,
311                      GLsizei height, GLsizei depth,
312                      const webgl::PackingInfo& pi, const void* data);
313 GLenum DoCompressedTexSubImage(gl::GLContext* gl, TexImageTarget target,
314                                GLint level, GLint xOffset, GLint yOffset,
315                                GLint zOffset, GLsizei width, GLsizei height,
316                                GLsizei depth, GLenum sizedUnpackFormat,
317                                GLsizei dataSize, const void* data);
318 
319 }  // namespace mozilla
320 
321 #endif  // WEBGL_TEXTURE_H_
322