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