WebGLTexture.cpp 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231
  1. /* -*- Mode: C++; tab-width: 20; 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. #include "WebGLTexture.h"
  6. #include <algorithm>
  7. #include "GLContext.h"
  8. #include "mozilla/dom/WebGLRenderingContextBinding.h"
  9. #include "mozilla/gfx/Logging.h"
  10. #include "mozilla/MathAlgorithms.h"
  11. #include "mozilla/Scoped.h"
  12. #include "mozilla/Unused.h"
  13. #include "ScopedGLHelpers.h"
  14. #include "WebGLContext.h"
  15. #include "WebGLContextUtils.h"
  16. #include "WebGLFramebuffer.h"
  17. #include "WebGLSampler.h"
  18. #include "WebGLTexelConversions.h"
  19. namespace mozilla {
  20. /*static*/ const WebGLTexture::ImageInfo WebGLTexture::ImageInfo::kUndefined;
  21. ////////////////////////////////////////
  22. template <typename T>
  23. static inline T&
  24. Mutable(const T& x)
  25. {
  26. return const_cast<T&>(x);
  27. }
  28. void
  29. WebGLTexture::ImageInfo::Clear()
  30. {
  31. if (!IsDefined())
  32. return;
  33. OnRespecify();
  34. Mutable(mFormat) = LOCAL_GL_NONE;
  35. Mutable(mWidth) = 0;
  36. Mutable(mHeight) = 0;
  37. Mutable(mDepth) = 0;
  38. MOZ_ASSERT(!IsDefined());
  39. }
  40. WebGLTexture::ImageInfo&
  41. WebGLTexture::ImageInfo::operator =(const ImageInfo& a)
  42. {
  43. Mutable(mFormat) = a.mFormat;
  44. Mutable(mWidth) = a.mWidth;
  45. Mutable(mHeight) = a.mHeight;
  46. Mutable(mDepth) = a.mDepth;
  47. mIsDataInitialized = a.mIsDataInitialized;
  48. // But *don't* transfer mAttachPoints!
  49. MOZ_ASSERT(a.mAttachPoints.empty());
  50. OnRespecify();
  51. return *this;
  52. }
  53. bool
  54. WebGLTexture::ImageInfo::IsPowerOfTwo() const
  55. {
  56. return mozilla::IsPowerOfTwo(mWidth) &&
  57. mozilla::IsPowerOfTwo(mHeight) &&
  58. mozilla::IsPowerOfTwo(mDepth);
  59. }
  60. void
  61. WebGLTexture::ImageInfo::AddAttachPoint(WebGLFBAttachPoint* attachPoint)
  62. {
  63. const auto pair = mAttachPoints.insert(attachPoint);
  64. DebugOnly<bool> didInsert = pair.second;
  65. MOZ_ASSERT(didInsert);
  66. }
  67. void
  68. WebGLTexture::ImageInfo::RemoveAttachPoint(WebGLFBAttachPoint* attachPoint)
  69. {
  70. DebugOnly<size_t> numElemsErased = mAttachPoints.erase(attachPoint);
  71. MOZ_ASSERT_IF(IsDefined(), numElemsErased == 1);
  72. }
  73. void
  74. WebGLTexture::ImageInfo::OnRespecify() const
  75. {
  76. for (auto cur : mAttachPoints) {
  77. cur->OnBackingStoreRespecified();
  78. }
  79. }
  80. size_t
  81. WebGLTexture::ImageInfo::MemoryUsage() const
  82. {
  83. if (!IsDefined())
  84. return 0;
  85. const auto bytesPerTexel = mFormat->format->estimatedBytesPerPixel;
  86. return size_t(mWidth) * size_t(mHeight) * size_t(mDepth) * bytesPerTexel;
  87. }
  88. void
  89. WebGLTexture::ImageInfo::SetIsDataInitialized(bool isDataInitialized, WebGLTexture* tex)
  90. {
  91. MOZ_ASSERT(tex);
  92. MOZ_ASSERT(this >= &tex->mImageInfoArr[0]);
  93. MOZ_ASSERT(this < &tex->mImageInfoArr[kMaxLevelCount * kMaxFaceCount]);
  94. mIsDataInitialized = isDataInitialized;
  95. tex->InvalidateResolveCache();
  96. }
  97. ////////////////////////////////////////
  98. JSObject*
  99. WebGLTexture::WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) {
  100. return dom::WebGLTextureBinding::Wrap(cx, this, givenProto);
  101. }
  102. WebGLTexture::WebGLTexture(WebGLContext* webgl, GLuint tex)
  103. : WebGLRefCountedObject(webgl)
  104. , mGLName(tex)
  105. , mTarget(LOCAL_GL_NONE)
  106. , mFaceCount(0)
  107. , mMinFilter(LOCAL_GL_NEAREST_MIPMAP_LINEAR)
  108. , mMagFilter(LOCAL_GL_LINEAR)
  109. , mWrapS(LOCAL_GL_REPEAT)
  110. , mWrapT(LOCAL_GL_REPEAT)
  111. , mImmutable(false)
  112. , mImmutableLevelCount(0)
  113. , mBaseMipmapLevel(0)
  114. , mMaxMipmapLevel(1000)
  115. , mTexCompareMode(LOCAL_GL_NONE)
  116. , mIsResolved(false)
  117. , mResolved_Swizzle(nullptr)
  118. {
  119. mContext->mTextures.insertBack(this);
  120. }
  121. void
  122. WebGLTexture::Delete()
  123. {
  124. for (auto& cur : mImageInfoArr) {
  125. cur.Clear();
  126. }
  127. mContext->MakeContextCurrent();
  128. mContext->gl->fDeleteTextures(1, &mGLName);
  129. LinkedListElement<WebGLTexture>::removeFrom(mContext->mTextures);
  130. }
  131. size_t
  132. WebGLTexture::MemoryUsage() const
  133. {
  134. if (IsDeleted())
  135. return 0;
  136. size_t accum = 0;
  137. for (const auto& cur : mImageInfoArr) {
  138. accum += cur.MemoryUsage();
  139. }
  140. return accum;
  141. }
  142. void
  143. WebGLTexture::SetImageInfo(ImageInfo* target, const ImageInfo& newInfo)
  144. {
  145. *target = newInfo;
  146. InvalidateResolveCache();
  147. }
  148. void
  149. WebGLTexture::SetImageInfosAtLevel(uint32_t level, const ImageInfo& newInfo)
  150. {
  151. for (uint8_t i = 0; i < mFaceCount; i++) {
  152. ImageInfoAtFace(i, level) = newInfo;
  153. }
  154. InvalidateResolveCache();
  155. }
  156. bool
  157. WebGLTexture::IsMipmapComplete(const char* funcName, uint32_t texUnit,
  158. bool* const out_initFailed)
  159. {
  160. *out_initFailed = false;
  161. MOZ_ASSERT(DoesMinFilterRequireMipmap());
  162. // GLES 3.0.4, p161
  163. uint32_t maxLevel;
  164. if (!MaxEffectiveMipmapLevel(texUnit, &maxLevel))
  165. return false;
  166. // "* `level_base <= level_max`"
  167. if (mBaseMipmapLevel > maxLevel)
  168. return false;
  169. // Make a copy so we can modify it.
  170. const ImageInfo& baseImageInfo = BaseImageInfo();
  171. // Reference dimensions based on the current level.
  172. uint32_t refWidth = baseImageInfo.mWidth;
  173. uint32_t refHeight = baseImageInfo.mHeight;
  174. uint32_t refDepth = baseImageInfo.mDepth;
  175. MOZ_ASSERT(refWidth && refHeight && refDepth);
  176. for (uint32_t level = mBaseMipmapLevel; level <= maxLevel; level++) {
  177. if (!EnsureLevelInitialized(funcName, level)) {
  178. *out_initFailed = true;
  179. return false;
  180. }
  181. // "A cube map texture is mipmap complete if each of the six texture images,
  182. // considered individually, is mipmap complete."
  183. for (uint8_t face = 0; face < mFaceCount; face++) {
  184. const ImageInfo& cur = ImageInfoAtFace(face, level);
  185. // "* The set of mipmap arrays `level_base` through `q` (where `q` is defined
  186. // the "Mipmapping" discussion of section 3.8.10) were each specified with
  187. // the same effective internal format."
  188. // "* The dimensions of the arrays follow the sequence described in the
  189. // "Mipmapping" discussion of section 3.8.10."
  190. if (cur.mWidth != refWidth ||
  191. cur.mHeight != refHeight ||
  192. cur.mDepth != refDepth ||
  193. cur.mFormat != baseImageInfo.mFormat)
  194. {
  195. return false;
  196. }
  197. }
  198. // GLES 3.0.4, p158:
  199. // "[...] until the last array is reached with dimension 1 x 1 x 1."
  200. if (mTarget == LOCAL_GL_TEXTURE_3D) {
  201. if (refWidth == 1 &&
  202. refHeight == 1 &&
  203. refDepth == 1)
  204. {
  205. break;
  206. }
  207. refDepth = std::max(uint32_t(1), refDepth / 2);
  208. } else {
  209. // TEXTURE_2D_ARRAY may have depth != 1, but that's normal.
  210. if (refWidth == 1 &&
  211. refHeight == 1)
  212. {
  213. break;
  214. }
  215. }
  216. refWidth = std::max(uint32_t(1), refWidth / 2);
  217. refHeight = std::max(uint32_t(1), refHeight / 2);
  218. }
  219. return true;
  220. }
  221. bool
  222. WebGLTexture::IsCubeComplete() const
  223. {
  224. // GLES 3.0.4, p161
  225. // "[...] a cube map texture is cube complete if the following conditions all hold
  226. // true:
  227. // * The `level_base` arrays of each of the six texture images making up the cube map
  228. // have identical, positive, and square dimensions.
  229. // * The `level_base` arrays were each specified with the same effective internal
  230. // format."
  231. // Note that "cube complete" does not imply "mipmap complete".
  232. const ImageInfo& reference = BaseImageInfo();
  233. if (!reference.IsDefined())
  234. return false;
  235. auto refWidth = reference.mWidth;
  236. auto refFormat = reference.mFormat;
  237. for (uint8_t face = 0; face < mFaceCount; face++) {
  238. const ImageInfo& cur = ImageInfoAtFace(face, mBaseMipmapLevel);
  239. if (!cur.IsDefined())
  240. return false;
  241. MOZ_ASSERT(cur.mDepth == 1);
  242. if (cur.mFormat != refFormat || // Check effective formats.
  243. cur.mWidth != refWidth || // Check both width and height against refWidth to
  244. cur.mHeight != refWidth) // to enforce positive and square dimensions.
  245. {
  246. return false;
  247. }
  248. }
  249. return true;
  250. }
  251. bool
  252. WebGLTexture::IsComplete(const char* funcName, uint32_t texUnit,
  253. const char** const out_reason, bool* const out_initFailed)
  254. {
  255. *out_initFailed = false;
  256. const auto maxLevel = kMaxLevelCount - 1;
  257. if (mBaseMipmapLevel > maxLevel) {
  258. *out_reason = "`level_base` too high.";
  259. return false;
  260. }
  261. if (!EnsureLevelInitialized(funcName, mBaseMipmapLevel)) {
  262. *out_initFailed = true;
  263. return false;
  264. }
  265. // Texture completeness is established at GLES 3.0.4, p160-161.
  266. // "[A] texture is complete unless any of the following conditions hold true:"
  267. // "* Any dimension of the `level_base` array is not positive."
  268. const ImageInfo& baseImageInfo = BaseImageInfo();
  269. if (!baseImageInfo.IsDefined()) {
  270. // In case of undefined texture image, we don't print any message because this is
  271. // a very common and often legitimate case (asynchronous texture loading).
  272. *out_reason = nullptr;
  273. return false;
  274. }
  275. if (!baseImageInfo.mWidth || !baseImageInfo.mHeight || !baseImageInfo.mDepth) {
  276. *out_reason = "The dimensions of `level_base` are not all positive.";
  277. return false;
  278. }
  279. // "* The texture is a cube map texture, and is not cube complete."
  280. if (IsCubeMap() && !IsCubeComplete()) {
  281. *out_reason = "Cubemaps must be \"cube complete\".";
  282. return false;
  283. }
  284. WebGLSampler* sampler = mContext->mBoundSamplers[texUnit];
  285. TexMinFilter minFilter = sampler ? sampler->mMinFilter : mMinFilter;
  286. TexMagFilter magFilter = sampler ? sampler->mMagFilter : mMagFilter;
  287. // "* The minification filter requires a mipmap (is neither NEAREST nor LINEAR) and
  288. // the texture is not mipmap complete."
  289. const bool requiresMipmap = (minFilter != LOCAL_GL_NEAREST &&
  290. minFilter != LOCAL_GL_LINEAR);
  291. if (requiresMipmap && !IsMipmapComplete(funcName, texUnit, out_initFailed)) {
  292. if (*out_initFailed)
  293. return false;
  294. *out_reason = "Because the minification filter requires mipmapping, the texture"
  295. " must be \"mipmap complete\".";
  296. return false;
  297. }
  298. const bool isMinFilteringNearest = (minFilter == LOCAL_GL_NEAREST ||
  299. minFilter == LOCAL_GL_NEAREST_MIPMAP_NEAREST);
  300. const bool isMagFilteringNearest = (magFilter == LOCAL_GL_NEAREST);
  301. const bool isFilteringNearestOnly = (isMinFilteringNearest && isMagFilteringNearest);
  302. if (!isFilteringNearestOnly) {
  303. auto formatUsage = baseImageInfo.mFormat;
  304. auto format = formatUsage->format;
  305. bool isFilterable = formatUsage->isFilterable;
  306. // "* The effective internal format specified for the texture arrays is a sized
  307. // internal depth or depth and stencil format, the value of
  308. // TEXTURE_COMPARE_MODE is NONE[1], and either the magnification filter is not
  309. // NEAREST, or the minification filter is neither NEAREST nor
  310. // NEAREST_MIPMAP_NEAREST."
  311. // [1]: This sounds suspect, but is explicitly noted in the change log for GLES
  312. // 3.0.1:
  313. // "* Clarify that a texture is incomplete if it has a depth component, no
  314. // shadow comparison, and linear filtering (also Bug 9481)."
  315. if (format->d && mTexCompareMode != LOCAL_GL_NONE) {
  316. isFilterable = true;
  317. }
  318. // "* The effective internal format specified for the texture arrays is a sized
  319. // internal color format that is not texture-filterable, and either the
  320. // magnification filter is not NEAREST or the minification filter is neither
  321. // NEAREST nor NEAREST_MIPMAP_NEAREST."
  322. // Since all (GLES3) unsized color formats are filterable just like their sized
  323. // equivalents, we don't have to care whether its sized or not.
  324. if (!isFilterable) {
  325. *out_reason = "Because minification or magnification filtering is not NEAREST"
  326. " or NEAREST_MIPMAP_NEAREST, and the texture's format must be"
  327. " \"texture-filterable\".";
  328. return false;
  329. }
  330. }
  331. // Texture completeness is effectively (though not explicitly) amended for GLES2 by
  332. // the "Texture Access" section under $3.8 "Fragment Shaders". This also applies to
  333. // vertex shaders, as noted on GLES 2.0.25, p41.
  334. if (!mContext->IsWebGL2()) {
  335. // GLES 2.0.25, p87-88:
  336. // "Calling a sampler from a fragment shader will return (R,G,B,A)=(0,0,0,1) if
  337. // any of the following conditions are true:"
  338. // "* A two-dimensional sampler is called, the minification filter is one that
  339. // requires a mipmap[...], and the sampler's associated texture object is not
  340. // complete[.]"
  341. // (already covered)
  342. // "* A two-dimensional sampler is called, the minification filter is not one that
  343. // requires a mipmap (either NEAREST nor[sic] LINEAR), and either dimension of
  344. // the level zero array of the associated texture object is not positive."
  345. // (already covered)
  346. // "* A two-dimensional sampler is called, the corresponding texture image is a
  347. // non-power-of-two image[...], and either the texture wrap mode is not
  348. // CLAMP_TO_EDGE, or the minification filter is neither NEAREST nor LINEAR."
  349. // "* A cube map sampler is called, any of the corresponding texture images are
  350. // non-power-of-two images, and either the texture wrap mode is not
  351. // CLAMP_TO_EDGE, or the minification filter is neither NEAREST nor LINEAR."
  352. if (!baseImageInfo.IsPowerOfTwo()) {
  353. TexWrap wrapS = sampler ? sampler->mWrapS : mWrapS;
  354. TexWrap wrapT = sampler ? sampler->mWrapT : mWrapT;
  355. // "either the texture wrap mode is not CLAMP_TO_EDGE"
  356. if (wrapS != LOCAL_GL_CLAMP_TO_EDGE ||
  357. wrapT != LOCAL_GL_CLAMP_TO_EDGE)
  358. {
  359. *out_reason = "Non-power-of-two textures must have a wrap mode of"
  360. " CLAMP_TO_EDGE.";
  361. return false;
  362. }
  363. // "or the minification filter is neither NEAREST nor LINEAR"
  364. if (requiresMipmap) {
  365. *out_reason = "Mipmapping requires power-of-two textures.";
  366. return false;
  367. }
  368. }
  369. // "* A cube map sampler is called, and either the corresponding cube map texture
  370. // image is not cube complete, or TEXTURE_MIN_FILTER is one that requires a
  371. // mipmap and the texture is not mipmap cube complete."
  372. // (already covered)
  373. }
  374. return true;
  375. }
  376. bool
  377. WebGLTexture::MaxEffectiveMipmapLevel(uint32_t texUnit, uint32_t* const out) const
  378. {
  379. WebGLSampler* sampler = mContext->mBoundSamplers[texUnit];
  380. TexMinFilter minFilter = sampler ? sampler->mMinFilter : mMinFilter;
  381. if (minFilter == LOCAL_GL_NEAREST ||
  382. minFilter == LOCAL_GL_LINEAR)
  383. {
  384. // No extra mips used.
  385. *out = mBaseMipmapLevel;
  386. return true;
  387. }
  388. const auto& imageInfo = BaseImageInfo();
  389. if (!imageInfo.IsDefined())
  390. return false;
  391. uint32_t maxLevelBySize = mBaseMipmapLevel + imageInfo.PossibleMipmapLevels() - 1;
  392. *out = std::min<uint32_t>(maxLevelBySize, mMaxMipmapLevel);
  393. return true;
  394. }
  395. bool
  396. WebGLTexture::GetFakeBlackType(const char* funcName, uint32_t texUnit,
  397. FakeBlackType* const out_fakeBlack)
  398. {
  399. const char* incompleteReason;
  400. bool initFailed = false;
  401. if (!IsComplete(funcName, texUnit, &incompleteReason, &initFailed)) {
  402. if (initFailed) {
  403. mContext->ErrorOutOfMemory("%s: Failed to initialize texture data.",
  404. funcName);
  405. return false; // The world just exploded.
  406. }
  407. if (incompleteReason) {
  408. mContext->GenerateWarning("%s: Active texture %u for target 0x%04x is"
  409. " 'incomplete', and will be rendered as"
  410. " RGBA(0,0,0,1), as per the GLES 2.0.24 $3.8.2: %s",
  411. funcName, texUnit, mTarget.get(),
  412. incompleteReason);
  413. }
  414. *out_fakeBlack = FakeBlackType::RGBA0001;
  415. return true;
  416. }
  417. *out_fakeBlack = FakeBlackType::None;
  418. return true;
  419. }
  420. static void
  421. SetSwizzle(gl::GLContext* gl, TexTarget target, const GLint* swizzle)
  422. {
  423. static const GLint kNoSwizzle[4] = { LOCAL_GL_RED, LOCAL_GL_GREEN, LOCAL_GL_BLUE,
  424. LOCAL_GL_ALPHA };
  425. if (!swizzle) {
  426. swizzle = kNoSwizzle;
  427. } else if (!gl->IsSupported(gl::GLFeature::texture_swizzle)) {
  428. MOZ_CRASH("GFX: Needs swizzle feature to swizzle!");
  429. }
  430. gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_SWIZZLE_R, swizzle[0]);
  431. gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_SWIZZLE_G, swizzle[1]);
  432. gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_SWIZZLE_B, swizzle[2]);
  433. gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_SWIZZLE_A, swizzle[3]);
  434. }
  435. bool
  436. WebGLTexture::ResolveForDraw(const char* funcName, uint32_t texUnit,
  437. FakeBlackType* const out_fakeBlack)
  438. {
  439. if (!mIsResolved) {
  440. if (!GetFakeBlackType(funcName, texUnit, &mResolved_FakeBlack))
  441. return false;
  442. // Check which swizzle we should use. Since the texture must be complete at this
  443. // point, just grab the format off any valid image.
  444. const GLint* newSwizzle = nullptr;
  445. if (mResolved_FakeBlack == FakeBlackType::None) {
  446. const auto& cur = ImageInfoAtFace(0, mBaseMipmapLevel);
  447. newSwizzle = cur.mFormat->textureSwizzleRGBA;
  448. }
  449. // Only set the swizzle if it changed since last time we did it.
  450. if (newSwizzle != mResolved_Swizzle) {
  451. mResolved_Swizzle = newSwizzle;
  452. // Set the new swizzle!
  453. mContext->gl->fActiveTexture(LOCAL_GL_TEXTURE0 + texUnit);
  454. SetSwizzle(mContext->gl, mTarget, mResolved_Swizzle);
  455. mContext->gl->fActiveTexture(LOCAL_GL_TEXTURE0 + mContext->mActiveTexture);
  456. }
  457. mIsResolved = true;
  458. }
  459. *out_fakeBlack = mResolved_FakeBlack;
  460. return true;
  461. }
  462. bool
  463. WebGLTexture::EnsureImageDataInitialized(const char* funcName, TexImageTarget target,
  464. uint32_t level)
  465. {
  466. auto& imageInfo = ImageInfoAt(target, level);
  467. if (!imageInfo.IsDefined())
  468. return true;
  469. if (imageInfo.IsDataInitialized())
  470. return true;
  471. return InitializeImageData(funcName, target, level);
  472. }
  473. bool
  474. WebGLTexture::EnsureLevelInitialized(const char* funcName, uint32_t level)
  475. {
  476. if (mTarget != LOCAL_GL_TEXTURE_CUBE_MAP)
  477. return EnsureImageDataInitialized(funcName, mTarget.get(), level);
  478. for (GLenum texImageTarget = LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X;
  479. texImageTarget <= LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
  480. ++texImageTarget)
  481. {
  482. if (!EnsureImageDataInitialized(funcName, texImageTarget, level))
  483. return false;
  484. }
  485. return true;
  486. }
  487. static void
  488. ZeroANGLEDepthTexture(WebGLContext* webgl, GLuint tex,
  489. const webgl::FormatUsageInfo* usage, uint32_t width,
  490. uint32_t height)
  491. {
  492. const auto& format = usage->format;
  493. GLenum attachPoint = 0;
  494. GLbitfield clearBits = 0;
  495. if (format->d) {
  496. attachPoint = LOCAL_GL_DEPTH_ATTACHMENT;
  497. clearBits |= LOCAL_GL_DEPTH_BUFFER_BIT;
  498. }
  499. if (format->s) {
  500. attachPoint = (format->d ? LOCAL_GL_DEPTH_STENCIL_ATTACHMENT
  501. : LOCAL_GL_STENCIL_ATTACHMENT);
  502. clearBits |= LOCAL_GL_STENCIL_BUFFER_BIT;
  503. }
  504. MOZ_RELEASE_ASSERT(attachPoint && clearBits, "GFX: No bits cleared.");
  505. ////
  506. const auto& gl = webgl->gl;
  507. MOZ_ASSERT(gl->IsCurrent());
  508. gl::ScopedFramebuffer scopedFB(gl);
  509. const gl::ScopedBindFramebuffer scopedBindFB(gl, scopedFB.FB());
  510. gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, attachPoint, LOCAL_GL_TEXTURE_2D,
  511. tex, 0);
  512. const auto& status = gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
  513. MOZ_RELEASE_ASSERT(status == LOCAL_GL_FRAMEBUFFER_COMPLETE);
  514. ////
  515. const bool fakeNoAlpha = false;
  516. webgl->ForceClearFramebufferWithDefaultValues(clearBits, fakeNoAlpha);
  517. }
  518. static bool
  519. ZeroTextureData(WebGLContext* webgl, const char* funcName, GLuint tex,
  520. TexImageTarget target, uint32_t level,
  521. const webgl::FormatUsageInfo* usage, uint32_t width, uint32_t height,
  522. uint32_t depth)
  523. {
  524. // This has two usecases:
  525. // 1. Lazy zeroing of uninitialized textures:
  526. // a. Before draw, when FakeBlack isn't viable. (TexStorage + Draw*)
  527. // b. Before partial upload. (TexStorage + TexSubImage)
  528. // 2. Zero subrects from out-of-bounds blits. (CopyTex(Sub)Image)
  529. // We have no sympathy for any of these cases.
  530. // "Doctor, it hurts when I do this!" "Well don't do that!"
  531. webgl->GenerateWarning("%s: This operation requires zeroing texture data. This is"
  532. " slow.",
  533. funcName);
  534. gl::GLContext* gl = webgl->GL();
  535. gl->MakeCurrent();
  536. GLenum scopeBindTarget;
  537. switch (target.get()) {
  538. case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
  539. case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
  540. case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
  541. case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
  542. case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
  543. case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
  544. scopeBindTarget = LOCAL_GL_TEXTURE_CUBE_MAP;
  545. break;
  546. default:
  547. scopeBindTarget = target.get();
  548. break;
  549. }
  550. const gl::ScopedBindTexture scopeBindTexture(gl, tex, scopeBindTarget);
  551. auto compression = usage->format->compression;
  552. if (compression) {
  553. auto sizedFormat = usage->format->sizedFormat;
  554. MOZ_RELEASE_ASSERT(sizedFormat, "GFX: texture sized format not set");
  555. const auto fnSizeInBlocks = [](CheckedUint32 pixels, uint8_t pixelsPerBlock) {
  556. return RoundUpToMultipleOf(pixels, pixelsPerBlock) / pixelsPerBlock;
  557. };
  558. const auto widthBlocks = fnSizeInBlocks(width, compression->blockWidth);
  559. const auto heightBlocks = fnSizeInBlocks(height, compression->blockHeight);
  560. CheckedUint32 checkedByteCount = compression->bytesPerBlock;
  561. checkedByteCount *= widthBlocks;
  562. checkedByteCount *= heightBlocks;
  563. checkedByteCount *= depth;
  564. if (!checkedByteCount.isValid())
  565. return false;
  566. const size_t byteCount = checkedByteCount.value();
  567. UniqueBuffer zeros = calloc(1, byteCount);
  568. if (!zeros)
  569. return false;
  570. ScopedUnpackReset scopedReset(webgl);
  571. gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 1); // Don't bother with striding it
  572. // well.
  573. const auto error = DoCompressedTexSubImage(gl, target.get(), level, 0, 0, 0,
  574. width, height, depth, sizedFormat,
  575. byteCount, zeros.get());
  576. return !error;
  577. }
  578. const auto driverUnpackInfo = usage->idealUnpack;
  579. MOZ_RELEASE_ASSERT(driverUnpackInfo, "GFX: ideal unpack info not set.");
  580. if (webgl->IsExtensionEnabled(WebGLExtensionID::WEBGL_depth_texture) &&
  581. gl->IsANGLE() &&
  582. usage->format->d)
  583. {
  584. // ANGLE_depth_texture does not allow uploads, so we have to clear.
  585. // (Restriction because of D3D9)
  586. MOZ_ASSERT(target == LOCAL_GL_TEXTURE_2D);
  587. MOZ_ASSERT(level == 0);
  588. ZeroANGLEDepthTexture(webgl, tex, usage, width, height);
  589. return true;
  590. }
  591. const webgl::PackingInfo packing = driverUnpackInfo->ToPacking();
  592. const auto bytesPerPixel = webgl::BytesPerPixel(packing);
  593. CheckedUint32 checkedByteCount = bytesPerPixel;
  594. checkedByteCount *= width;
  595. checkedByteCount *= height;
  596. checkedByteCount *= depth;
  597. if (!checkedByteCount.isValid())
  598. return false;
  599. const size_t byteCount = checkedByteCount.value();
  600. UniqueBuffer zeros = calloc(1, byteCount);
  601. if (!zeros)
  602. return false;
  603. ScopedUnpackReset scopedReset(webgl);
  604. gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 1); // Don't bother with striding it well.
  605. const auto error = DoTexSubImage(gl, target, level, 0, 0, 0, width, height, depth,
  606. packing, zeros.get());
  607. return !error;
  608. }
  609. bool
  610. WebGLTexture::InitializeImageData(const char* funcName, TexImageTarget target,
  611. uint32_t level)
  612. {
  613. auto& imageInfo = ImageInfoAt(target, level);
  614. MOZ_ASSERT(imageInfo.IsDefined());
  615. MOZ_ASSERT(!imageInfo.IsDataInitialized());
  616. const auto& usage = imageInfo.mFormat;
  617. const auto& width = imageInfo.mWidth;
  618. const auto& height = imageInfo.mHeight;
  619. const auto& depth = imageInfo.mDepth;
  620. if (!ZeroTextureData(mContext, funcName, mGLName, target, level, usage, width, height,
  621. depth))
  622. {
  623. return false;
  624. }
  625. imageInfo.SetIsDataInitialized(true, this);
  626. return true;
  627. }
  628. void
  629. WebGLTexture::ClampLevelBaseAndMax()
  630. {
  631. if (!mImmutable)
  632. return;
  633. // GLES 3.0.4, p158:
  634. // "For immutable-format textures, `level_base` is clamped to the range
  635. // `[0, levels-1]`, `level_max` is then clamped to the range `
  636. // `[level_base, levels-1]`, where `levels` is the parameter passed to
  637. // TexStorage* for the texture object."
  638. mBaseMipmapLevel = Clamp<uint32_t>(mBaseMipmapLevel, 0, mImmutableLevelCount - 1);
  639. mMaxMipmapLevel = Clamp<uint32_t>(mMaxMipmapLevel, mBaseMipmapLevel,
  640. mImmutableLevelCount - 1);
  641. }
  642. void
  643. WebGLTexture::PopulateMipChain(uint32_t firstLevel, uint32_t lastLevel)
  644. {
  645. const ImageInfo& baseImageInfo = ImageInfoAtFace(0, firstLevel);
  646. MOZ_ASSERT(baseImageInfo.IsDefined());
  647. uint32_t refWidth = baseImageInfo.mWidth;
  648. uint32_t refHeight = baseImageInfo.mHeight;
  649. uint32_t refDepth = baseImageInfo.mDepth;
  650. if (!refWidth || !refHeight || !refDepth)
  651. return;
  652. for (uint32_t level = firstLevel + 1; level <= lastLevel; level++) {
  653. bool isMinimal = (refWidth == 1 &&
  654. refHeight == 1);
  655. if (mTarget == LOCAL_GL_TEXTURE_3D) {
  656. isMinimal &= (refDepth == 1);
  657. }
  658. // Higher levels are unaffected.
  659. if (isMinimal)
  660. break;
  661. refWidth = std::max(uint32_t(1), refWidth / 2);
  662. refHeight = std::max(uint32_t(1), refHeight / 2);
  663. if (mTarget == LOCAL_GL_TEXTURE_3D) { // But not TEXTURE_2D_ARRAY!
  664. refDepth = std::max(uint32_t(1), refDepth / 2);
  665. }
  666. const ImageInfo cur(baseImageInfo.mFormat, refWidth, refHeight, refDepth,
  667. baseImageInfo.IsDataInitialized());
  668. SetImageInfosAtLevel(level, cur);
  669. }
  670. }
  671. //////////////////////////////////////////////////////////////////////////////////////////
  672. // GL calls
  673. bool
  674. WebGLTexture::BindTexture(TexTarget texTarget)
  675. {
  676. if (IsDeleted()) {
  677. mContext->ErrorInvalidOperation("bindTexture: Cannot bind a deleted object.");
  678. return false;
  679. }
  680. const bool isFirstBinding = !HasEverBeenBound();
  681. if (!isFirstBinding && mTarget != texTarget) {
  682. mContext->ErrorInvalidOperation("bindTexture: This texture has already been bound"
  683. " to a different target.");
  684. return false;
  685. }
  686. mTarget = texTarget;
  687. mContext->gl->fBindTexture(mTarget.get(), mGLName);
  688. if (isFirstBinding) {
  689. mFaceCount = IsCubeMap() ? 6 : 1;
  690. gl::GLContext* gl = mContext->gl;
  691. // Thanks to the WebKit people for finding this out: GL_TEXTURE_WRAP_R
  692. // is not present in GLES 2, but is present in GL and it seems as if for
  693. // cube maps we need to set it to GL_CLAMP_TO_EDGE to get the expected
  694. // GLES behavior.
  695. // If we are WebGL 2 though, we'll want to leave it as REPEAT.
  696. const bool hasWrapR = gl->IsSupported(gl::GLFeature::texture_3D);
  697. if (IsCubeMap() && hasWrapR && !mContext->IsWebGL2()) {
  698. gl->fTexParameteri(texTarget.get(), LOCAL_GL_TEXTURE_WRAP_R,
  699. LOCAL_GL_CLAMP_TO_EDGE);
  700. }
  701. }
  702. return true;
  703. }
  704. void
  705. WebGLTexture::GenerateMipmap(TexTarget texTarget)
  706. {
  707. // GLES 3.0.4 p160:
  708. // "Mipmap generation replaces texel array levels level base + 1 through q with arrays
  709. // derived from the level base array, regardless of their previous contents. All
  710. // other mipmap arrays, including the level base array, are left unchanged by this
  711. // computation."
  712. const ImageInfo& baseImageInfo = BaseImageInfo();
  713. if (!baseImageInfo.IsDefined()) {
  714. mContext->ErrorInvalidOperation("generateMipmap: The base level of the texture is"
  715. " not defined.");
  716. return;
  717. }
  718. if (IsCubeMap() && !IsCubeComplete()) {
  719. mContext->ErrorInvalidOperation("generateMipmap: Cube maps must be \"cube"
  720. " complete\".");
  721. return;
  722. }
  723. if (!mContext->IsWebGL2() && !baseImageInfo.IsPowerOfTwo()) {
  724. mContext->ErrorInvalidOperation("generateMipmap: The base level of the texture"
  725. " does not have power-of-two dimensions.");
  726. return;
  727. }
  728. auto format = baseImageInfo.mFormat->format;
  729. if (format->compression) {
  730. mContext->ErrorInvalidOperation("generateMipmap: Texture data at base level is"
  731. " compressed.");
  732. return;
  733. }
  734. if (format->d) {
  735. mContext->ErrorInvalidOperation("generateMipmap: Depth textures are not"
  736. " supported.");
  737. return;
  738. }
  739. // OpenGL ES 3.0.4 p160:
  740. // If the level base array was not specified with an unsized internal format from
  741. // table 3.3 or a sized internal format that is both color-renderable and
  742. // texture-filterable according to table 3.13, an INVALID_OPERATION error
  743. // is generated.
  744. const auto usage = baseImageInfo.mFormat;
  745. bool canGenerateMipmap = (usage->IsRenderable() && usage->isFilterable);
  746. switch (usage->format->effectiveFormat) {
  747. case webgl::EffectiveFormat::Luminance8:
  748. case webgl::EffectiveFormat::Alpha8:
  749. case webgl::EffectiveFormat::Luminance8Alpha8:
  750. // Non-color-renderable formats from Table 3.3.
  751. canGenerateMipmap = true;
  752. break;
  753. default:
  754. break;
  755. }
  756. if (!canGenerateMipmap) {
  757. mContext->ErrorInvalidOperation("generateMipmap: Texture at base level is not unsized"
  758. " internal format or is not"
  759. " color-renderable or texture-filterable.");
  760. return;
  761. }
  762. // Done with validation. Do the operation.
  763. mContext->MakeContextCurrent();
  764. gl::GLContext* gl = mContext->gl;
  765. if (gl->WorkAroundDriverBugs()) {
  766. // bug 696495 - to work around failures in the texture-mips.html test on various drivers, we
  767. // set the minification filter before calling glGenerateMipmap. This should not carry a significant performance
  768. // overhead so we do it unconditionally.
  769. //
  770. // note that the choice of GL_NEAREST_MIPMAP_NEAREST really matters. See Chromium bug 101105.
  771. gl->fTexParameteri(texTarget.get(), LOCAL_GL_TEXTURE_MIN_FILTER,
  772. LOCAL_GL_NEAREST_MIPMAP_NEAREST);
  773. gl->fGenerateMipmap(texTarget.get());
  774. gl->fTexParameteri(texTarget.get(), LOCAL_GL_TEXTURE_MIN_FILTER,
  775. mMinFilter.get());
  776. } else {
  777. gl->fGenerateMipmap(texTarget.get());
  778. }
  779. // Record the results.
  780. // Note that we don't use MaxEffectiveMipmapLevel() here, since that returns
  781. // mBaseMipmapLevel if the min filter doesn't require mipmaps.
  782. const uint32_t maxLevel = mBaseMipmapLevel + baseImageInfo.PossibleMipmapLevels() - 1;
  783. PopulateMipChain(mBaseMipmapLevel, maxLevel);
  784. }
  785. JS::Value
  786. WebGLTexture::GetTexParameter(TexTarget texTarget, GLenum pname)
  787. {
  788. mContext->MakeContextCurrent();
  789. GLint i = 0;
  790. GLfloat f = 0.0f;
  791. switch (pname) {
  792. case LOCAL_GL_TEXTURE_MIN_FILTER:
  793. return JS::NumberValue(uint32_t(mMinFilter.get()));
  794. case LOCAL_GL_TEXTURE_MAG_FILTER:
  795. return JS::NumberValue(uint32_t(mMagFilter.get()));
  796. case LOCAL_GL_TEXTURE_WRAP_S:
  797. return JS::NumberValue(uint32_t(mWrapS.get()));
  798. case LOCAL_GL_TEXTURE_WRAP_T:
  799. return JS::NumberValue(uint32_t(mWrapT.get()));
  800. case LOCAL_GL_TEXTURE_BASE_LEVEL:
  801. return JS::NumberValue(mBaseMipmapLevel);
  802. case LOCAL_GL_TEXTURE_COMPARE_MODE:
  803. return JS::NumberValue(uint32_t(mTexCompareMode));
  804. case LOCAL_GL_TEXTURE_MAX_LEVEL:
  805. return JS::NumberValue(mMaxMipmapLevel);
  806. case LOCAL_GL_TEXTURE_IMMUTABLE_FORMAT:
  807. return JS::BooleanValue(mImmutable);
  808. case LOCAL_GL_TEXTURE_IMMUTABLE_LEVELS:
  809. return JS::NumberValue(uint32_t(mImmutableLevelCount));
  810. case LOCAL_GL_TEXTURE_COMPARE_FUNC:
  811. case LOCAL_GL_TEXTURE_WRAP_R:
  812. mContext->gl->fGetTexParameteriv(texTarget.get(), pname, &i);
  813. return JS::NumberValue(uint32_t(i));
  814. case LOCAL_GL_TEXTURE_MAX_ANISOTROPY_EXT:
  815. case LOCAL_GL_TEXTURE_MAX_LOD:
  816. case LOCAL_GL_TEXTURE_MIN_LOD:
  817. mContext->gl->fGetTexParameterfv(texTarget.get(), pname, &f);
  818. return JS::NumberValue(float(f));
  819. default:
  820. MOZ_CRASH("GFX: Unhandled pname.");
  821. }
  822. }
  823. bool
  824. WebGLTexture::IsTexture() const
  825. {
  826. return HasEverBeenBound() && !IsDeleted();
  827. }
  828. // Here we have to support all pnames with both int and float params.
  829. // See this discussion:
  830. // https://www.khronos.org/webgl/public-mailing-list/archives/1008/msg00014.html
  831. void
  832. WebGLTexture::TexParameter(TexTarget texTarget, GLenum pname, const FloatOrInt& param)
  833. {
  834. bool isPNameValid = false;
  835. switch (pname) {
  836. // GLES 2.0.25 p76:
  837. case LOCAL_GL_TEXTURE_WRAP_S:
  838. case LOCAL_GL_TEXTURE_WRAP_T:
  839. case LOCAL_GL_TEXTURE_MIN_FILTER:
  840. case LOCAL_GL_TEXTURE_MAG_FILTER:
  841. isPNameValid = true;
  842. break;
  843. // GLES 3.0.4 p149-150:
  844. case LOCAL_GL_TEXTURE_BASE_LEVEL:
  845. case LOCAL_GL_TEXTURE_COMPARE_MODE:
  846. case LOCAL_GL_TEXTURE_COMPARE_FUNC:
  847. case LOCAL_GL_TEXTURE_MAX_LEVEL:
  848. case LOCAL_GL_TEXTURE_MAX_LOD:
  849. case LOCAL_GL_TEXTURE_MIN_LOD:
  850. case LOCAL_GL_TEXTURE_WRAP_R:
  851. if (mContext->IsWebGL2())
  852. isPNameValid = true;
  853. break;
  854. case LOCAL_GL_TEXTURE_MAX_ANISOTROPY_EXT:
  855. if (mContext->IsExtensionEnabled(WebGLExtensionID::EXT_texture_filter_anisotropic))
  856. isPNameValid = true;
  857. break;
  858. }
  859. if (!isPNameValid) {
  860. mContext->ErrorInvalidEnumInfo("texParameter: pname", pname);
  861. return;
  862. }
  863. ////////////////
  864. // Validate params and invalidate if needed.
  865. bool paramBadEnum = false;
  866. bool paramBadValue = false;
  867. switch (pname) {
  868. case LOCAL_GL_TEXTURE_BASE_LEVEL:
  869. case LOCAL_GL_TEXTURE_MAX_LEVEL:
  870. paramBadValue = (param.i < 0);
  871. break;
  872. case LOCAL_GL_TEXTURE_COMPARE_MODE:
  873. paramBadValue = (param.i != LOCAL_GL_NONE &&
  874. param.i != LOCAL_GL_COMPARE_REF_TO_TEXTURE);
  875. break;
  876. case LOCAL_GL_TEXTURE_COMPARE_FUNC:
  877. switch (param.i) {
  878. case LOCAL_GL_LEQUAL:
  879. case LOCAL_GL_GEQUAL:
  880. case LOCAL_GL_LESS:
  881. case LOCAL_GL_GREATER:
  882. case LOCAL_GL_EQUAL:
  883. case LOCAL_GL_NOTEQUAL:
  884. case LOCAL_GL_ALWAYS:
  885. case LOCAL_GL_NEVER:
  886. break;
  887. default:
  888. paramBadValue = true;
  889. break;
  890. }
  891. break;
  892. case LOCAL_GL_TEXTURE_MIN_FILTER:
  893. switch (param.i) {
  894. case LOCAL_GL_NEAREST:
  895. case LOCAL_GL_LINEAR:
  896. case LOCAL_GL_NEAREST_MIPMAP_NEAREST:
  897. case LOCAL_GL_LINEAR_MIPMAP_NEAREST:
  898. case LOCAL_GL_NEAREST_MIPMAP_LINEAR:
  899. case LOCAL_GL_LINEAR_MIPMAP_LINEAR:
  900. break;
  901. default:
  902. paramBadEnum = true;
  903. break;
  904. }
  905. break;
  906. case LOCAL_GL_TEXTURE_MAG_FILTER:
  907. switch (param.i) {
  908. case LOCAL_GL_NEAREST:
  909. case LOCAL_GL_LINEAR:
  910. break;
  911. default:
  912. paramBadEnum = true;
  913. break;
  914. }
  915. break;
  916. case LOCAL_GL_TEXTURE_WRAP_S:
  917. case LOCAL_GL_TEXTURE_WRAP_T:
  918. case LOCAL_GL_TEXTURE_WRAP_R:
  919. switch (param.i) {
  920. case LOCAL_GL_CLAMP_TO_EDGE:
  921. case LOCAL_GL_MIRRORED_REPEAT:
  922. case LOCAL_GL_REPEAT:
  923. break;
  924. default:
  925. paramBadEnum = true;
  926. break;
  927. }
  928. break;
  929. case LOCAL_GL_TEXTURE_MAX_ANISOTROPY_EXT:
  930. if (param.f < 1.0f)
  931. paramBadValue = true;
  932. break;
  933. }
  934. if (paramBadEnum) {
  935. if (!param.isFloat) {
  936. mContext->ErrorInvalidEnum("texParameteri: pname 0x%04x: Invalid param"
  937. " 0x%04x.",
  938. pname, param.i);
  939. } else {
  940. mContext->ErrorInvalidEnum("texParameterf: pname 0x%04x: Invalid param %g.",
  941. pname, param.f);
  942. }
  943. return;
  944. }
  945. if (paramBadValue) {
  946. if (!param.isFloat) {
  947. mContext->ErrorInvalidValue("texParameteri: pname 0x%04x: Invalid param %i"
  948. " (0x%x).",
  949. pname, param.i, param.i);
  950. } else {
  951. mContext->ErrorInvalidValue("texParameterf: pname 0x%04x: Invalid param %g.",
  952. pname, param.f);
  953. }
  954. return;
  955. }
  956. ////////////////
  957. // Store any needed values
  958. FloatOrInt clamped = param;
  959. switch (pname) {
  960. case LOCAL_GL_TEXTURE_BASE_LEVEL:
  961. mBaseMipmapLevel = clamped.i;
  962. ClampLevelBaseAndMax();
  963. clamped = FloatOrInt(GLint(mBaseMipmapLevel));
  964. break;
  965. case LOCAL_GL_TEXTURE_MAX_LEVEL:
  966. mMaxMipmapLevel = clamped.i;
  967. ClampLevelBaseAndMax();
  968. clamped = FloatOrInt(GLint(mMaxMipmapLevel));
  969. break;
  970. case LOCAL_GL_TEXTURE_MIN_FILTER:
  971. mMinFilter = clamped.i;
  972. break;
  973. case LOCAL_GL_TEXTURE_MAG_FILTER:
  974. mMagFilter = clamped.i;
  975. break;
  976. case LOCAL_GL_TEXTURE_WRAP_S:
  977. mWrapS = clamped.i;
  978. break;
  979. case LOCAL_GL_TEXTURE_WRAP_T:
  980. mWrapT = clamped.i;
  981. break;
  982. case LOCAL_GL_TEXTURE_COMPARE_MODE:
  983. mTexCompareMode = clamped.i;
  984. break;
  985. // We don't actually need to store the WRAP_R, since it doesn't change texture
  986. // completeness rules.
  987. }
  988. // Only a couple of pnames don't need to invalidate our resolve status cache.
  989. switch (pname) {
  990. case LOCAL_GL_TEXTURE_MAX_ANISOTROPY_EXT:
  991. case LOCAL_GL_TEXTURE_WRAP_R:
  992. break;
  993. default:
  994. InvalidateResolveCache();
  995. break;
  996. }
  997. ////////////////
  998. mContext->MakeContextCurrent();
  999. if (!clamped.isFloat)
  1000. mContext->gl->fTexParameteri(texTarget.get(), pname, clamped.i);
  1001. else
  1002. mContext->gl->fTexParameterf(texTarget.get(), pname, clamped.f);
  1003. }
  1004. void WebGLTexture::Truncate() {
  1005. for (auto& cur : mImageInfoArr) {
  1006. SetImageInfo(&cur, ImageInfo());
  1007. }
  1008. }
  1009. ////////////////////////////////////////////////////////////////////////////////
  1010. NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLTexture)
  1011. NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLTexture, AddRef)
  1012. NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLTexture, Release)
  1013. } // namespace mozilla