forked from mirrors/gecko-dev
		
	Differential Revision: https://phabricator.services.mozilla.com/D21106 --HG-- extra : rebase_source : ea3f51c2c11247114deccbc86e90fb02b8a97257
		
			
				
	
	
		
			357 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			357 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/* -*- 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 "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, 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->ErrorInvalidEnumInfo("texTarget", rawTexTarget);
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  WebGLTexture* tex = webgl->ActiveBoundTextureForTarget(texTarget);
 | 
						|
  if (!tex) {
 | 
						|
    webgl->ErrorInvalidOperation("No texture is bound to this target.");
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  *out_texTarget = texTarget;
 | 
						|
  *out_tex = tex;
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
bool ValidateTexImageTarget(WebGLContext* webgl, 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->ErrorInvalidEnumInfo("texImageTarget", rawTexImageTarget);
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  WebGLTexture* tex =
 | 
						|
      webgl->ActiveBoundTextureForTexImageTarget(texImageTarget);
 | 
						|
  if (!tex) {
 | 
						|
    webgl->ErrorInvalidOperation("No texture is bound to this target.");
 | 
						|
    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;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
//////////////////////////////////////////////////////////////////////////////////////////
 | 
						|
// GL calls
 | 
						|
 | 
						|
void WebGLContext::BindTexture(GLenum rawTarget, WebGLTexture* newTex) {
 | 
						|
  const FuncScope funcScope(*this, "bindTexture");
 | 
						|
  if (IsContextLost()) return;
 | 
						|
 | 
						|
  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.
 | 
						|
  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("target", rawTarget);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  const TexTarget texTarget(rawTarget);
 | 
						|
  if (newTex) {
 | 
						|
    if (!newTex->BindTexture(texTarget)) return;
 | 
						|
  } else {
 | 
						|
    gl->fBindTexture(texTarget.get(), 0);
 | 
						|
  }
 | 
						|
 | 
						|
  *currentTexPtr = newTex;
 | 
						|
}
 | 
						|
 | 
						|
void WebGLContext::GenerateMipmap(GLenum rawTexTarget) {
 | 
						|
  const FuncScope funcScope(*this, "generateMipmap");
 | 
						|
  const uint8_t funcDims = 0;
 | 
						|
 | 
						|
  TexTarget texTarget;
 | 
						|
  WebGLTexture* tex;
 | 
						|
  if (!ValidateTexTarget(this, funcDims, rawTexTarget, &texTarget, &tex))
 | 
						|
    return;
 | 
						|
 | 
						|
  tex->GenerateMipmap();
 | 
						|
}
 | 
						|
 | 
						|
JS::Value WebGLContext::GetTexParameter(GLenum rawTexTarget, GLenum pname) {
 | 
						|
  const FuncScope funcScope(*this, "getTexParameter");
 | 
						|
  const uint8_t funcDims = 0;
 | 
						|
 | 
						|
  TexTarget texTarget;
 | 
						|
  WebGLTexture* tex;
 | 
						|
  if (!ValidateTexTarget(this, funcDims, rawTexTarget, &texTarget, &tex))
 | 
						|
    return JS::NullValue();
 | 
						|
 | 
						|
  if (!IsTexParamValid(pname)) {
 | 
						|
    ErrorInvalidEnumInfo("pname", pname);
 | 
						|
    return JS::NullValue();
 | 
						|
  }
 | 
						|
 | 
						|
  return tex->GetTexParameter(texTarget, pname);
 | 
						|
}
 | 
						|
 | 
						|
void WebGLContext::TexParameter_base(GLenum rawTexTarget, GLenum pname,
 | 
						|
                                     const FloatOrInt& param) {
 | 
						|
  const FuncScope funcScope(*this, "texParameter");
 | 
						|
  const uint8_t funcDims = 0;
 | 
						|
 | 
						|
  TexTarget texTarget;
 | 
						|
  WebGLTexture* tex;
 | 
						|
  if (!ValidateTexTarget(this, funcDims, rawTexTarget, &texTarget, &tex))
 | 
						|
    return;
 | 
						|
 | 
						|
  tex->TexParameter(texTarget, pname, param);
 | 
						|
}
 | 
						|
 | 
						|
//////////////////////////////////////////////////////////////////////////////////////////
 | 
						|
// Uploads
 | 
						|
 | 
						|
void WebGLContext::CompressedTexImage(uint8_t funcDims, GLenum rawTarget,
 | 
						|
                                      GLint level, GLenum internalFormat,
 | 
						|
                                      GLsizei width, GLsizei height,
 | 
						|
                                      GLsizei depth, GLint border,
 | 
						|
                                      const TexImageSource& src,
 | 
						|
                                      const Maybe<GLsizei>& expectedImageSize) {
 | 
						|
  TexImageTarget target;
 | 
						|
  WebGLTexture* tex;
 | 
						|
  if (!ValidateTexImageTarget(this, funcDims, rawTarget, &target, &tex)) return;
 | 
						|
 | 
						|
  tex->CompressedTexImage(target, level, internalFormat, width, height, depth,
 | 
						|
                          border, src, expectedImageSize);
 | 
						|
}
 | 
						|
 | 
						|
void WebGLContext::CompressedTexSubImage(
 | 
						|
    uint8_t funcDims, GLenum rawTarget, GLint level, GLint xOffset,
 | 
						|
    GLint yOffset, GLint zOffset, GLsizei width, GLsizei height, GLsizei depth,
 | 
						|
    GLenum unpackFormat, const TexImageSource& src,
 | 
						|
    const Maybe<GLsizei>& expectedImageSize) {
 | 
						|
  TexImageTarget target;
 | 
						|
  WebGLTexture* tex;
 | 
						|
  if (!ValidateTexImageTarget(this, funcDims, rawTarget, &target, &tex)) return;
 | 
						|
 | 
						|
  tex->CompressedTexSubImage(target, level, xOffset, yOffset, zOffset, width,
 | 
						|
                             height, depth, unpackFormat, src,
 | 
						|
                             expectedImageSize);
 | 
						|
}
 | 
						|
 | 
						|
////
 | 
						|
 | 
						|
void WebGLContext::CopyTexImage2D(GLenum rawTarget, GLint level,
 | 
						|
                                  GLenum internalFormat, GLint x, GLint y,
 | 
						|
                                  GLsizei width, GLsizei height, GLint border) {
 | 
						|
  const FuncScope funcScope(*this, "copyTexImage2D");
 | 
						|
  const uint8_t funcDims = 2;
 | 
						|
 | 
						|
  TexImageTarget target;
 | 
						|
  WebGLTexture* tex;
 | 
						|
  if (!ValidateTexImageTarget(this, funcDims, rawTarget, &target, &tex)) return;
 | 
						|
 | 
						|
  tex->CopyTexImage2D(target, level, internalFormat, x, y, width, height,
 | 
						|
                      border);
 | 
						|
}
 | 
						|
 | 
						|
void WebGLContext::CopyTexSubImage(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, funcDims, rawTarget, &target, &tex)) return;
 | 
						|
 | 
						|
  tex->CopyTexSubImage(target, level, xOffset, yOffset, zOffset, x, y, width,
 | 
						|
                       height);
 | 
						|
}
 | 
						|
 | 
						|
////
 | 
						|
 | 
						|
void WebGLContext::TexImage(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, funcDims, rawTarget, &target, &tex)) return;
 | 
						|
 | 
						|
  const webgl::PackingInfo pi = {unpackFormat, unpackType};
 | 
						|
  tex->TexImage(target, level, internalFormat, width, height, depth, border, pi,
 | 
						|
                src);
 | 
						|
}
 | 
						|
 | 
						|
void WebGLContext::TexSubImage(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, funcDims, rawTarget, &target, &tex)) return;
 | 
						|
 | 
						|
  const webgl::PackingInfo pi = {unpackFormat, unpackType};
 | 
						|
  tex->TexSubImage(target, level, xOffset, yOffset, zOffset, width, height,
 | 
						|
                   depth, pi, src);
 | 
						|
}
 | 
						|
 | 
						|
}  // namespace mozilla
 |