diff options
Diffstat (limited to 'dom/canvas/WebGLContextTextures.cpp')
-rw-r--r-- | dom/canvas/WebGLContextTextures.cpp | 415 |
1 files changed, 415 insertions, 0 deletions
diff --git a/dom/canvas/WebGLContextTextures.cpp b/dom/canvas/WebGLContextTextures.cpp new file mode 100644 index 000000000..30716438f --- /dev/null +++ b/dom/canvas/WebGLContextTextures.cpp @@ -0,0 +1,415 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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 "WebGLVertexAttribData.h" +#include "WebGLShader.h" +#include "WebGLProgram.h" +#include "WebGLUniformLocation.h" +#include "WebGLFramebuffer.h" +#include "WebGLRenderbuffer.h" +#include "WebGLShaderPrecisionFormat.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 <algorithm> + +// 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/dom/ToJSValue.h" +#include "mozilla/EndianUtils.h" + +namespace mozilla { + +static bool +IsValidTexTarget(WebGLContext* webgl, uint8_t funcDims, GLenum rawTexTarget, + TexTarget* const out) +{ + uint8_t targetDims; + + switch (rawTexTarget) { + case LOCAL_GL_TEXTURE_2D: + case LOCAL_GL_TEXTURE_CUBE_MAP: + targetDims = 2; + break; + + case LOCAL_GL_TEXTURE_3D: + case LOCAL_GL_TEXTURE_2D_ARRAY: + if (!webgl->IsWebGL2()) + return false; + + targetDims = 3; + break; + + default: + return false; + } + + // Some funcs (like GenerateMipmap) doesn't know the dimension, so don't check it. + if (funcDims && targetDims != funcDims) + return false; + + *out = rawTexTarget; + return true; +} + +static bool +IsValidTexImageTarget(WebGLContext* webgl, uint8_t funcDims, GLenum rawTexImageTarget, + TexImageTarget* const out) +{ + uint8_t targetDims; + + switch (rawTexImageTarget) { + case LOCAL_GL_TEXTURE_2D: + case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + targetDims = 2; + break; + + case LOCAL_GL_TEXTURE_3D: + case LOCAL_GL_TEXTURE_2D_ARRAY: + if (!webgl->IsWebGL2()) + return false; + + targetDims = 3; + break; + + default: + return false; + } + + if (targetDims != funcDims) + return false; + + *out = rawTexImageTarget; + return true; +} + +bool +ValidateTexTarget(WebGLContext* webgl, const char* funcName, uint8_t funcDims, + GLenum rawTexTarget, TexTarget* const out_texTarget, + WebGLTexture** const out_tex) +{ + if (webgl->IsContextLost()) + return false; + + TexTarget texTarget; + if (!IsValidTexTarget(webgl, funcDims, rawTexTarget, &texTarget)) { + webgl->ErrorInvalidEnum("%s: Invalid texTarget.", funcName); + return false; + } + + WebGLTexture* tex = webgl->ActiveBoundTextureForTarget(texTarget); + if (!tex) { + webgl->ErrorInvalidOperation("%s: No texture is bound to this target.", funcName); + return false; + } + + *out_texTarget = texTarget; + *out_tex = tex; + return true; +} + +bool +ValidateTexImageTarget(WebGLContext* webgl, const char* funcName, uint8_t funcDims, + GLenum rawTexImageTarget, TexImageTarget* const out_texImageTarget, + WebGLTexture** const out_tex) +{ + if (webgl->IsContextLost()) + return false; + + TexImageTarget texImageTarget; + if (!IsValidTexImageTarget(webgl, funcDims, rawTexImageTarget, &texImageTarget)) { + webgl->ErrorInvalidEnum("%s: Invalid texImageTarget.", funcName); + return false; + } + + WebGLTexture* tex = webgl->ActiveBoundTextureForTexImageTarget(texImageTarget); + if (!tex) { + webgl->ErrorInvalidOperation("%s: No texture is bound to this target.", funcName); + return false; + } + + *out_texImageTarget = texImageTarget; + *out_tex = tex; + return true; +} + +/*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; + } +} + +void +WebGLContext::InvalidateResolveCacheForTextureWithTexUnit(const GLuint texUnit) +{ + if (mBound2DTextures[texUnit]) + mBound2DTextures[texUnit]->InvalidateResolveCache(); + if (mBoundCubeMapTextures[texUnit]) + mBoundCubeMapTextures[texUnit]->InvalidateResolveCache(); + if (mBound3DTextures[texUnit]) + mBound3DTextures[texUnit]->InvalidateResolveCache(); + if (mBound2DArrayTextures[texUnit]) + mBound2DArrayTextures[texUnit]->InvalidateResolveCache(); +} + +////////////////////////////////////////////////////////////////////////////////////////// +// GL calls + +void +WebGLContext::BindTexture(GLenum rawTarget, WebGLTexture* newTex) +{ + if (IsContextLost()) + return; + + if (newTex && !ValidateObject("bindTexture", *newTex)) + return; + + // Need to check rawTarget first before comparing against newTex->Target() as + // newTex->Target() returns a TexTarget, which will assert on invalid value. + WebGLRefPtr<WebGLTexture>* 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("bindTexture: target", rawTarget); + return; + } + + const TexTarget texTarget(rawTarget); + + MakeContextCurrent(); + + if (newTex) { + if (!newTex->BindTexture(texTarget)) + return; + } else { + gl->fBindTexture(texTarget.get(), 0); + } + + *currentTexPtr = newTex; +} + +void +WebGLContext::GenerateMipmap(GLenum rawTexTarget) +{ + const char funcName[] = "generateMipmap"; + const uint8_t funcDims = 0; + + TexTarget texTarget; + WebGLTexture* tex; + if (!ValidateTexTarget(this, funcName, funcDims, rawTexTarget, &texTarget, &tex)) + return; + + tex->GenerateMipmap(texTarget); +} + +JS::Value +WebGLContext::GetTexParameter(GLenum rawTexTarget, GLenum pname) +{ + const char funcName[] = "getTexParameter"; + const uint8_t funcDims = 0; + + TexTarget texTarget; + WebGLTexture* tex; + if (!ValidateTexTarget(this, funcName, funcDims, rawTexTarget, &texTarget, &tex)) + return JS::NullValue(); + + if (!IsTexParamValid(pname)) { + ErrorInvalidEnumInfo("getTexParameter: pname", pname); + return JS::NullValue(); + } + + return tex->GetTexParameter(texTarget, pname); +} + +bool +WebGLContext::IsTexture(WebGLTexture* tex) +{ + if (!ValidateIsObject("isTexture", tex)) + return false; + + return tex->IsTexture(); +} + +void +WebGLContext::TexParameter_base(GLenum rawTexTarget, GLenum pname, + const FloatOrInt& param) +{ + const char funcName[] = "texParameter"; + const uint8_t funcDims = 0; + + TexTarget texTarget; + WebGLTexture* tex; + if (!ValidateTexTarget(this, funcName, funcDims, rawTexTarget, &texTarget, &tex)) + return; + + tex->TexParameter(texTarget, pname, param); +} + +////////////////////////////////////////////////////////////////////////////////////////// +// Uploads + +void +WebGLContext::CompressedTexImage(const char* funcName, uint8_t funcDims, GLenum rawTarget, + GLint level, GLenum internalFormat, GLsizei width, + GLsizei height, GLsizei depth, GLint border, + const TexImageSource& src) +{ + TexImageTarget target; + WebGLTexture* tex; + if (!ValidateTexImageTarget(this, funcName, funcDims, rawTarget, &target, &tex)) + return; + + tex->CompressedTexImage(funcName, target, level, internalFormat, width, height, depth, + border, src); +} + +void +WebGLContext::CompressedTexSubImage(const char* funcName, uint8_t funcDims, + GLenum rawTarget, GLint level, GLint xOffset, + GLint yOffset, GLint zOffset, GLsizei width, + GLsizei height, GLsizei depth, GLenum unpackFormat, + const TexImageSource& src) +{ + TexImageTarget target; + WebGLTexture* tex; + if (!ValidateTexImageTarget(this, funcName, funcDims, rawTarget, &target, &tex)) + return; + + tex->CompressedTexSubImage(funcName, target, level, xOffset, yOffset, zOffset, width, + height, depth, unpackFormat, src); +} + +//// + +void +WebGLContext::CopyTexImage2D(GLenum rawTarget, GLint level, GLenum internalFormat, + GLint x, GLint y, GLsizei width, GLsizei height, + GLint border) +{ + const char funcName[] = "copyTexImage2D"; + const uint8_t funcDims = 2; + + TexImageTarget target; + WebGLTexture* tex; + if (!ValidateTexImageTarget(this, funcName, funcDims, rawTarget, &target, &tex)) + return; + + tex->CopyTexImage2D(target, level, internalFormat, x, y, width, height, border); +} + +void +WebGLContext::CopyTexSubImage(const char* funcName, uint8_t funcDims, GLenum rawTarget, + GLint level, GLint xOffset, GLint yOffset, GLint zOffset, + GLint x, GLint y, GLsizei width, GLsizei height) +{ + TexImageTarget target; + WebGLTexture* tex; + if (!ValidateTexImageTarget(this, funcName, funcDims, rawTarget, &target, &tex)) + return; + + tex->CopyTexSubImage(funcName, target, level, xOffset, yOffset, zOffset, x, y, width, + height); +} + +//// + +void +WebGLContext::TexImage(const char* funcName, uint8_t funcDims, GLenum rawTarget, + GLint level, GLenum internalFormat, GLsizei width, GLsizei height, + GLsizei depth, GLint border, GLenum unpackFormat, + GLenum unpackType, const TexImageSource& src) +{ + TexImageTarget target; + WebGLTexture* tex; + if (!ValidateTexImageTarget(this, funcName, funcDims, rawTarget, &target, &tex)) + return; + + const webgl::PackingInfo pi = {unpackFormat, unpackType}; + tex->TexImage(funcName, target, level, internalFormat, width, height, depth, border, + pi, src); +} + +void +WebGLContext::TexSubImage(const char* funcName, uint8_t funcDims, GLenum rawTarget, + GLint level, GLint xOffset, GLint yOffset, GLint zOffset, + GLsizei width, GLsizei height, GLsizei depth, + GLenum unpackFormat, GLenum unpackType, + const TexImageSource& src) +{ + TexImageTarget target; + WebGLTexture* tex; + if (!ValidateTexImageTarget(this, funcName, funcDims, rawTarget, &target, &tex)) + return; + + const webgl::PackingInfo pi = {unpackFormat, unpackType}; + tex->TexSubImage(funcName, target, level, xOffset, yOffset, zOffset, width, height, + depth, pi, src); +} + +} // namespace mozilla |