/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "WebGLContext.h" #include "WebGLContextUtils.h" #include "WebGLBuffer.h" #include "WebGLShader.h" #include "WebGLProgram.h" #include "WebGLFramebuffer.h" #include "WebGLRenderbuffer.h" #include "WebGLTexture.h" #include "WebGLExtensions.h" #include "WebGLVertexArray.h" #include "nsString.h" #include "nsDebug.h" #include "nsReadableUtils.h" #include "gfxContext.h" #include "gfxPlatform.h" #include "GLContext.h" #include "nsContentUtils.h" #include "nsError.h" #include "nsLayoutUtils.h" #include "CanvasUtils.h" #include "gfxUtils.h" #include "jsfriendapi.h" #include "WebGLTexelConversions.h" #include "WebGLValidateStrings.h" #include // needed to check if current OS is lower than 10.7 #if defined(MOZ_WIDGET_COCOA) # include "nsCocoaFeatures.h" #endif #include "mozilla/DebugOnly.h" #include "mozilla/dom/BindingUtils.h" #include "mozilla/dom/ImageData.h" #include "mozilla/EndianUtils.h" namespace mozilla { /*virtual*/ bool WebGLContext::IsTexParamValid(GLenum pname) const { switch (pname) { case LOCAL_GL_TEXTURE_MIN_FILTER: case LOCAL_GL_TEXTURE_MAG_FILTER: case LOCAL_GL_TEXTURE_WRAP_S: case LOCAL_GL_TEXTURE_WRAP_T: return true; case LOCAL_GL_TEXTURE_MAX_ANISOTROPY_EXT: return IsExtensionEnabled( WebGLExtensionID::EXT_texture_filter_anisotropic); default: return false; } } ////////////////////////////////////////////////////////////////////////////////////////// // GL calls void WebGLContext::BindTexture(GLenum rawTarget, WebGLTexture* newTex) { FuncScope funcScope(*this, "bindTexture"); if (IsContextLost()) return; funcScope.mBindFailureGuard = true; if (newTex && !ValidateObject("tex", *newTex)) return; // Need to check rawTarget first before comparing against newTex->Target() as // newTex->Target() returns a TexTarget, which will assert on invalid value. RefPtr* currentTexPtr = nullptr; switch (rawTarget) { case LOCAL_GL_TEXTURE_2D: currentTexPtr = &mBound2DTextures[mActiveTexture]; break; case LOCAL_GL_TEXTURE_CUBE_MAP: currentTexPtr = &mBoundCubeMapTextures[mActiveTexture]; break; case LOCAL_GL_TEXTURE_3D: if (IsWebGL2()) currentTexPtr = &mBound3DTextures[mActiveTexture]; break; case LOCAL_GL_TEXTURE_2D_ARRAY: if (IsWebGL2()) currentTexPtr = &mBound2DArrayTextures[mActiveTexture]; break; } if (!currentTexPtr) { ErrorInvalidEnumInfo("target", rawTarget); return; } const TexTarget texTarget(rawTarget); if (newTex) { if (!newTex->BindTexture(texTarget)) return; } else { gl->fBindTexture(texTarget.get(), 0); } *currentTexPtr = newTex; funcScope.mBindFailureGuard = false; } void WebGLContext::GenerateMipmap(GLenum texTarget) { const FuncScope funcScope(*this, "generateMipmap"); const auto& tex = GetActiveTex(texTarget); if (!tex) return; tex->GenerateMipmap(); } Maybe WebGLContext::GetTexParameter(const WebGLTexture& tex, GLenum pname) const { const FuncScope funcScope(*this, "getTexParameter"); if (!IsTexParamValid(pname)) { ErrorInvalidEnumInfo("pname", pname); return Nothing(); } return tex.GetTexParameter(pname); } void WebGLContext::TexParameter_base(GLenum texTarget, GLenum pname, const FloatOrInt& param) { const FuncScope funcScope(*this, "texParameter"); const auto& tex = GetActiveTex(texTarget); if (!tex) return; tex->TexParameter(texTarget, pname, param); } ////////////////////////////////////////////////////////////////////////////////////////// // Uploads WebGLTexture* WebGLContext::GetActiveTex(const GLenum texTarget) const { const auto* list = &mBound2DTextures; switch (texTarget) { case LOCAL_GL_TEXTURE_2D: break; case LOCAL_GL_TEXTURE_CUBE_MAP: list = &mBoundCubeMapTextures; break; case LOCAL_GL_TEXTURE_3D: list = IsWebGL2() ? &mBound3DTextures : nullptr; break; case LOCAL_GL_TEXTURE_2D_ARRAY: list = IsWebGL2() ? &mBound2DArrayTextures : nullptr; break; default: list = nullptr; } if (!list) { ErrorInvalidEnumArg("target", texTarget); return nullptr; } const auto& tex = (*list)[mActiveTexture]; if (!tex) { GenerateError(LOCAL_GL_INVALID_OPERATION, "No texture bound to %s[%u].", EnumString(texTarget).c_str(), mActiveTexture); return nullptr; } return tex; } void WebGLContext::TexStorage(GLenum texTarget, uint32_t levels, GLenum internalFormat, uvec3 size) const { const FuncScope funcScope(*this, "texStorage(Multisample)?"); if (!IsTexTarget3D(texTarget)) { size.z = 1; } const auto tex = GetActiveTex(texTarget); if (!tex) return; tex->TexStorage(texTarget, levels, internalFormat, size); } void WebGLContext::TexImage(uint32_t level, GLenum respecFormat, uvec3 offset, const webgl::PackingInfo& pi, const webgl::TexUnpackBlobDesc& src) const { const WebGLContext::FuncScope funcScope( *this, bool(respecFormat) ? "texImage" : "texSubImage"); const bool isUploadFromPbo = bool(src.pboOffset); const bool isPboBound = bool(mBoundPixelUnpackBuffer); if (isUploadFromPbo != isPboBound) { GenerateError(LOCAL_GL_INVALID_OPERATION, "Tex upload from %s but PIXEL_UNPACK_BUFFER %s bound.", isUploadFromPbo ? "PBO" : "non-PBO", isPboBound ? "was" : "was not"); return; } if (respecFormat) { offset = {0, 0, 0}; } const auto texTarget = ImageToTexTarget(src.imageTarget); const auto tex = GetActiveTex(texTarget); if (!tex) return; tex->TexImage(level, respecFormat, offset, pi, src); } void WebGLContext::CompressedTexImage(bool sub, GLenum imageTarget, uint32_t level, GLenum format, uvec3 offset, uvec3 size, const Range& src, const uint32_t pboImageSize, const Maybe& pboOffset) const { const WebGLContext::FuncScope funcScope( *this, !sub ? "compressedTexImage" : "compressedTexSubImage"); if (!sub) { offset = {0, 0, 0}; } const auto texTarget = ImageToTexTarget(imageTarget); if (!IsTexTarget3D(texTarget)) { size.z = 1; } const auto tex = GetActiveTex(texTarget); if (!tex) return; tex->CompressedTexImage(sub, imageTarget, level, format, offset, size, src, pboImageSize, pboOffset); } void WebGLContext::CopyTexImage(GLenum imageTarget, uint32_t level, GLenum respecFormat, uvec3 dstOffset, const ivec2& srcOffset, const uvec2& size) const { const WebGLContext::FuncScope funcScope( *this, bool(respecFormat) ? "copyTexImage" : "copyTexSubImage"); if (respecFormat) { dstOffset = {0, 0, 0}; } const auto tex = GetActiveTex(ImageToTexTarget(imageTarget)); if (!tex) return; tex->CopyTexImage(imageTarget, level, respecFormat, dstOffset, srcOffset, size); } } // namespace mozilla