gecko-dev/dom/canvas/WebGLContextGL.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

1527 строки
43 KiB
C++
Исходник Обычный вид История

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2012-05-21 15:12:37 +04:00
/* 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 "WebGL2Context.h"
#include "WebGLContextUtils.h"
#include "WebGLBuffer.h"
#include "WebGLVertexAttribData.h"
#include "WebGLShader.h"
#include "WebGLProgram.h"
#include "WebGLFormats.h"
#include "WebGLFramebuffer.h"
#include "WebGLQuery.h"
#include "WebGLRenderbuffer.h"
#include "WebGLTexture.h"
#include "WebGLExtensions.h"
#include "WebGLVertexArray.h"
#include "nsDebug.h"
#include "nsReadableUtils.h"
#include "nsString.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/EndianUtils.h"
Bug 1207245 - part 6 - rename nsRefPtr<T> to RefPtr<T>; r=ehsan; a=Tomcat The bulk of this commit was generated with a script, executed at the top level of a typical source code checkout. The only non-machine-generated part was modifying MFBT's moz.build to reflect the new naming. CLOSED TREE makes big refactorings like this a piece of cake. # The main substitution. find . -name '*.cpp' -o -name '*.cc' -o -name '*.h' -o -name '*.mm' -o -name '*.idl'| \ xargs perl -p -i -e ' s/nsRefPtr\.h/RefPtr\.h/g; # handle includes s/nsRefPtr ?</RefPtr</g; # handle declarations and variables ' # Handle a special friend declaration in gfx/layers/AtomicRefCountedWithFinalize.h. perl -p -i -e 's/::nsRefPtr;/::RefPtr;/' gfx/layers/AtomicRefCountedWithFinalize.h # Handle nsRefPtr.h itself, a couple places that define constructors # from nsRefPtr, and code generators specially. We do this here, rather # than indiscriminantly s/nsRefPtr/RefPtr/, because that would rename # things like nsRefPtrHashtable. perl -p -i -e 's/nsRefPtr/RefPtr/g' \ mfbt/nsRefPtr.h \ xpcom/glue/nsCOMPtr.h \ xpcom/base/OwningNonNull.h \ ipc/ipdl/ipdl/lower.py \ ipc/ipdl/ipdl/builtin.py \ dom/bindings/Codegen.py \ python/lldbutils/lldbutils/utils.py # In our indiscriminate substitution above, we renamed # nsRefPtrGetterAddRefs, the class behind getter_AddRefs. Fix that up. find . -name '*.cpp' -o -name '*.h' -o -name '*.idl' | \ xargs perl -p -i -e 's/nsRefPtrGetterAddRefs/RefPtrGetterAddRefs/g' if [ -d .git ]; then git mv mfbt/nsRefPtr.h mfbt/RefPtr.h else hg mv mfbt/nsRefPtr.h mfbt/RefPtr.h fi --HG-- rename : mfbt/nsRefPtr.h => mfbt/RefPtr.h
2015-10-18 08:24:48 +03:00
#include "mozilla/RefPtr.h"
#include "mozilla/UniquePtrExtensions.h"
namespace mozilla {
using namespace mozilla::dom;
using namespace mozilla::gfx;
using namespace mozilla::gl;
//
// WebGL API
//
void WebGLContext::ActiveTexture(uint32_t texUnit) {
FuncScope funcScope(*this, "activeTexture");
if (IsContextLost()) return;
funcScope.mBindFailureGuard = true;
if (texUnit >= Limits().maxTexUnits) {
return ErrorInvalidEnum("Texture unit %u out of range (%u).", texUnit,
Limits().maxTexUnits);
}
mActiveTexture = texUnit;
gl->fActiveTexture(LOCAL_GL_TEXTURE0 + texUnit);
funcScope.mBindFailureGuard = false;
}
void WebGLContext::AttachShader(WebGLProgram& prog, WebGLShader& shader) {
FuncScope funcScope(*this, "attachShader");
if (IsContextLost()) return;
funcScope.mBindFailureGuard = true;
prog.AttachShader(shader);
funcScope.mBindFailureGuard = false;
}
void WebGLContext::BindAttribLocation(WebGLProgram& prog, GLuint location,
const std::string& name) const {
const FuncScope funcScope(*this, "bindAttribLocation");
if (IsContextLost()) return;
prog.BindAttribLocation(location, name);
}
void WebGLContext::BindFramebuffer(GLenum target, WebGLFramebuffer* wfb) {
FuncScope funcScope(*this, "bindFramebuffer");
if (IsContextLost()) return;
funcScope.mBindFailureGuard = true;
if (!ValidateFramebufferTarget(target)) return;
if (!wfb) {
gl->fBindFramebuffer(target, 0);
} else {
GLuint framebuffername = wfb->mGLName;
gl->fBindFramebuffer(target, framebuffername);
wfb->mHasBeenBound = true;
}
switch (target) {
case LOCAL_GL_FRAMEBUFFER:
mBoundDrawFramebuffer = wfb;
mBoundReadFramebuffer = wfb;
break;
case LOCAL_GL_DRAW_FRAMEBUFFER:
mBoundDrawFramebuffer = wfb;
break;
case LOCAL_GL_READ_FRAMEBUFFER:
mBoundReadFramebuffer = wfb;
break;
default:
return;
}
funcScope.mBindFailureGuard = false;
}
void WebGLContext::BlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) {
const FuncScope funcScope(*this, "blendEquationSeparate");
if (IsContextLost()) return;
if (!ValidateBlendEquationEnum(modeRGB, "modeRGB") ||
!ValidateBlendEquationEnum(modeAlpha, "modeAlpha")) {
return;
}
gl->fBlendEquationSeparate(modeRGB, modeAlpha);
}
static bool ValidateBlendFuncEnum(WebGLContext* webgl, GLenum factor,
const char* varName) {
switch (factor) {
case LOCAL_GL_ZERO:
case LOCAL_GL_ONE:
case LOCAL_GL_SRC_COLOR:
case LOCAL_GL_ONE_MINUS_SRC_COLOR:
case LOCAL_GL_DST_COLOR:
case LOCAL_GL_ONE_MINUS_DST_COLOR:
case LOCAL_GL_SRC_ALPHA:
case LOCAL_GL_ONE_MINUS_SRC_ALPHA:
case LOCAL_GL_DST_ALPHA:
case LOCAL_GL_ONE_MINUS_DST_ALPHA:
case LOCAL_GL_CONSTANT_COLOR:
case LOCAL_GL_ONE_MINUS_CONSTANT_COLOR:
case LOCAL_GL_CONSTANT_ALPHA:
case LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA:
case LOCAL_GL_SRC_ALPHA_SATURATE:
return true;
default:
webgl->ErrorInvalidEnumInfo(varName, factor);
return false;
}
}
static bool ValidateBlendFuncEnums(WebGLContext* webgl, GLenum srcRGB,
GLenum srcAlpha, GLenum dstRGB,
GLenum dstAlpha) {
if (!webgl->IsWebGL2()) {
if (dstRGB == LOCAL_GL_SRC_ALPHA_SATURATE ||
dstAlpha == LOCAL_GL_SRC_ALPHA_SATURATE) {
webgl->ErrorInvalidEnum(
"LOCAL_GL_SRC_ALPHA_SATURATE as a destination"
" blend function is disallowed in WebGL 1 (dstRGB ="
" 0x%04x, dstAlpha = 0x%04x).",
dstRGB, dstAlpha);
return false;
}
}
if (!ValidateBlendFuncEnum(webgl, srcRGB, "srcRGB") ||
!ValidateBlendFuncEnum(webgl, srcAlpha, "srcAlpha") ||
!ValidateBlendFuncEnum(webgl, dstRGB, "dstRGB") ||
!ValidateBlendFuncEnum(webgl, dstAlpha, "dstAlpha")) {
return false;
}
return true;
}
void WebGLContext::BlendFuncSeparate(GLenum srcRGB, GLenum dstRGB,
GLenum srcAlpha, GLenum dstAlpha) {
const FuncScope funcScope(*this, "blendFuncSeparate");
if (IsContextLost()) return;
if (!ValidateBlendFuncEnums(this, srcRGB, srcAlpha, dstRGB, dstAlpha)) return;
// note that we only check compatibity for the RGB enums, no need to for the
// Alpha enums, see "Section 6.8 forgetting to mention alpha factors?" thread
// on the public_webgl mailing list
if (!ValidateBlendFuncEnumsCompatibility(srcRGB, dstRGB, "srcRGB and dstRGB"))
return;
gl->fBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
}
GLenum WebGLContext::CheckFramebufferStatus(GLenum target) {
const FuncScope funcScope(*this, "checkFramebufferStatus");
if (IsContextLost()) return LOCAL_GL_FRAMEBUFFER_UNSUPPORTED;
if (!ValidateFramebufferTarget(target)) return 0;
WebGLFramebuffer* fb;
switch (target) {
case LOCAL_GL_FRAMEBUFFER:
case LOCAL_GL_DRAW_FRAMEBUFFER:
fb = mBoundDrawFramebuffer;
break;
case LOCAL_GL_READ_FRAMEBUFFER:
fb = mBoundReadFramebuffer;
break;
default:
MOZ_CRASH("GFX: Bad target.");
}
if (!fb) return LOCAL_GL_FRAMEBUFFER_COMPLETE;
return fb->CheckFramebufferStatus().get();
}
RefPtr<WebGLProgram> WebGLContext::CreateProgram() {
const FuncScope funcScope(*this, "createProgram");
if (IsContextLost()) return nullptr;
return new WebGLProgram(this);
}
RefPtr<WebGLShader> WebGLContext::CreateShader(GLenum type) {
const FuncScope funcScope(*this, "createShader");
if (IsContextLost()) return nullptr;
if (type != LOCAL_GL_VERTEX_SHADER && type != LOCAL_GL_FRAGMENT_SHADER) {
ErrorInvalidEnumInfo("type", type);
return nullptr;
}
return new WebGLShader(this, type);
}
void WebGLContext::CullFace(GLenum face) {
const FuncScope funcScope(*this, "cullFace");
if (IsContextLost()) return;
if (!ValidateFaceEnum(face)) return;
gl->fCullFace(face);
}
void WebGLContext::DetachShader(WebGLProgram& prog, const WebGLShader& shader) {
FuncScope funcScope(*this, "detachShader");
if (IsContextLost()) return;
funcScope.mBindFailureGuard = true;
prog.DetachShader(shader);
funcScope.mBindFailureGuard = false;
}
static bool ValidateComparisonEnum(WebGLContext& webgl, const GLenum func) {
switch (func) {
case LOCAL_GL_NEVER:
case LOCAL_GL_LESS:
case LOCAL_GL_LEQUAL:
case LOCAL_GL_GREATER:
case LOCAL_GL_GEQUAL:
case LOCAL_GL_EQUAL:
case LOCAL_GL_NOTEQUAL:
case LOCAL_GL_ALWAYS:
return true;
default:
webgl.ErrorInvalidEnumInfo("func", func);
return false;
}
}
void WebGLContext::DepthFunc(GLenum func) {
const FuncScope funcScope(*this, "depthFunc");
if (IsContextLost()) return;
if (!ValidateComparisonEnum(*this, func)) return;
gl->fDepthFunc(func);
}
void WebGLContext::DepthRange(GLfloat zNear, GLfloat zFar) {
const FuncScope funcScope(*this, "depthRange");
if (IsContextLost()) return;
if (zNear > zFar)
return ErrorInvalidOperation(
"the near value is greater than the far value!");
gl->fDepthRange(zNear, zFar);
}
// -
void WebGLContext::FramebufferAttach(const GLenum target,
const GLenum attachSlot,
const GLenum bindImageTarget,
const webgl::FbAttachInfo& toAttach) {
FuncScope funcScope(*this, "framebufferAttach");
funcScope.mBindFailureGuard = true;
const auto& limits = *mLimits;
if (!ValidateFramebufferTarget(target)) return;
auto fb = mBoundDrawFramebuffer;
if (target == LOCAL_GL_READ_FRAMEBUFFER) {
fb = mBoundReadFramebuffer;
}
if (!fb) return;
// `rb` needs no validation.
// `tex`
const auto& tex = toAttach.tex;
if (tex) {
const auto err = CheckFramebufferAttach(bindImageTarget, tex->mTarget.get(),
toAttach.mipLevel, toAttach.zLayer,
toAttach.zLayerCount, limits);
if (err) return;
}
auto safeToAttach = toAttach;
if (!IsWebGL2() &&
!IsExtensionEnabled(WebGLExtensionID::OES_fbo_render_mipmap)) {
safeToAttach.mipLevel = 0;
}
if (!IsExtensionEnabled(WebGLExtensionID::OVR_multiview2)) {
safeToAttach.isMultiview = false;
}
if (!fb->FramebufferAttach(attachSlot, safeToAttach)) return;
funcScope.mBindFailureGuard = false;
}
// -
void WebGLContext::FrontFace(GLenum mode) {
const FuncScope funcScope(*this, "frontFace");
if (IsContextLost()) return;
switch (mode) {
case LOCAL_GL_CW:
case LOCAL_GL_CCW:
break;
default:
return ErrorInvalidEnumInfo("mode", mode);
}
gl->fFrontFace(mode);
}
Maybe<double> WebGLContext::GetBufferParameter(GLenum target, GLenum pname) {
const FuncScope funcScope(*this, "getBufferParameter");
if (IsContextLost()) return Nothing();
const auto& slot = ValidateBufferSlot(target);
if (!slot) return Nothing();
const auto& buffer = *slot;
if (!buffer) {
ErrorInvalidOperation("Buffer for `target` is null.");
return Nothing();
}
switch (pname) {
case LOCAL_GL_BUFFER_SIZE:
return Some(buffer->ByteLength());
case LOCAL_GL_BUFFER_USAGE:
return Some(buffer->Usage());
default:
ErrorInvalidEnumInfo("pname", pname);
return Nothing();
}
}
Maybe<double> WebGLContext::GetFramebufferAttachmentParameter(
WebGLFramebuffer* const fb, GLenum attachment, GLenum pname) const {
const FuncScope funcScope(*this, "getFramebufferAttachmentParameter");
if (IsContextLost()) return Nothing();
if (fb) return fb->GetAttachmentParameter(attachment, pname);
////////////////////////////////////
if (!IsWebGL2()) {
ErrorInvalidOperation(
"Querying against the default framebuffer is not"
" allowed in WebGL 1.");
return Nothing();
}
switch (attachment) {
case LOCAL_GL_BACK:
case LOCAL_GL_DEPTH:
case LOCAL_GL_STENCIL:
break;
default:
ErrorInvalidEnum(
"For the default framebuffer, can only query COLOR, DEPTH,"
" or STENCIL.");
return Nothing();
}
switch (pname) {
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
switch (attachment) {
case LOCAL_GL_BACK:
break;
case LOCAL_GL_DEPTH:
if (!mOptions.depth) {
return Some(LOCAL_GL_NONE);
}
break;
case LOCAL_GL_STENCIL:
if (!mOptions.stencil) {
return Some(LOCAL_GL_NONE);
}
break;
default:
ErrorInvalidEnum(
"With the default framebuffer, can only query COLOR, DEPTH,"
" or STENCIL for GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE");
return Nothing();
}
return Some(LOCAL_GL_FRAMEBUFFER_DEFAULT);
////////////////
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
if (attachment == LOCAL_GL_BACK) return Some(8);
return Some(0);
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
if (attachment == LOCAL_GL_BACK) {
if (mOptions.alpha) {
return Some(8);
}
ErrorInvalidOperation(
"The default framebuffer doesn't contain an alpha buffer");
return Nothing();
}
return Some(0);
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
if (attachment == LOCAL_GL_DEPTH) {
if (mOptions.depth) {
return Some(24);
}
ErrorInvalidOperation(
"The default framebuffer doesn't contain an depth buffer");
return Nothing();
}
return Some(0);
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
if (attachment == LOCAL_GL_STENCIL) {
if (mOptions.stencil) {
return Some(8);
}
ErrorInvalidOperation(
"The default framebuffer doesn't contain an stencil buffer");
return Nothing();
}
return Some(0);
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
if (attachment == LOCAL_GL_STENCIL) {
if (mOptions.stencil) {
return Some(LOCAL_GL_UNSIGNED_INT);
}
ErrorInvalidOperation(
"The default framebuffer doesn't contain an stencil buffer");
} else if (attachment == LOCAL_GL_DEPTH) {
if (mOptions.depth) {
return Some(LOCAL_GL_UNSIGNED_NORMALIZED);
}
ErrorInvalidOperation(
"The default framebuffer doesn't contain an depth buffer");
} else { // LOCAL_GL_BACK
return Some(LOCAL_GL_UNSIGNED_NORMALIZED);
}
return Nothing();
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
if (attachment == LOCAL_GL_STENCIL) {
if (!mOptions.stencil) {
ErrorInvalidOperation(
"The default framebuffer doesn't contain an stencil buffer");
return Nothing();
}
} else if (attachment == LOCAL_GL_DEPTH) {
if (!mOptions.depth) {
ErrorInvalidOperation(
"The default framebuffer doesn't contain an depth buffer");
return Nothing();
}
}
return Some(LOCAL_GL_LINEAR);
}
ErrorInvalidEnumInfo("pname", pname);
return Nothing();
}
Maybe<double> WebGLContext::GetRenderbufferParameter(
const WebGLRenderbuffer& rb, GLenum pname) const {
const FuncScope funcScope(*this, "getRenderbufferParameter");
if (IsContextLost()) return Nothing();
switch (pname) {
case LOCAL_GL_RENDERBUFFER_SAMPLES:
if (!IsWebGL2()) break;
[[fallthrough]];
case LOCAL_GL_RENDERBUFFER_WIDTH:
case LOCAL_GL_RENDERBUFFER_HEIGHT:
case LOCAL_GL_RENDERBUFFER_RED_SIZE:
case LOCAL_GL_RENDERBUFFER_GREEN_SIZE:
case LOCAL_GL_RENDERBUFFER_BLUE_SIZE:
case LOCAL_GL_RENDERBUFFER_ALPHA_SIZE:
case LOCAL_GL_RENDERBUFFER_DEPTH_SIZE:
case LOCAL_GL_RENDERBUFFER_STENCIL_SIZE:
case LOCAL_GL_RENDERBUFFER_INTERNAL_FORMAT: {
// RB emulation means we have to ask the RB itself.
GLint i = rb.GetRenderbufferParameter(pname);
return Some(i);
}
default:
break;
}
ErrorInvalidEnumInfo("pname", pname);
return Nothing();
}
RefPtr<WebGLTexture> WebGLContext::CreateTexture() {
const FuncScope funcScope(*this, "createTexture");
if (IsContextLost()) return nullptr;
GLuint tex = 0;
gl->fGenTextures(1, &tex);
return new WebGLTexture(this, tex);
}
GLenum WebGLContext::GetError() {
const FuncScope funcScope(*this, "getError");
/* WebGL 1.0: Section 5.14.3: Setting and getting state:
* If the context's webgl context lost flag is set, returns
* CONTEXT_LOST_WEBGL the first time this method is called.
* Afterward, returns NO_ERROR until the context has been
* restored.
*
* WEBGL_lose_context:
* [When this extension is enabled: ] loseContext and
* restoreContext are allowed to generate INVALID_OPERATION errors
* even when the context is lost.
*/
auto err = mWebGLError;
mWebGLError = 0;
if (IsContextLost() || err) // Must check IsContextLost in all flow paths.
return err;
// Either no WebGL-side error, or it's already been cleared.
// UnderlyingGL-side errors, now.
err = gl->fGetError();
if (gl->IsContextLost()) {
CheckForContextLoss();
return GetError();
}
MOZ_ASSERT(err != LOCAL_GL_CONTEXT_LOST);
if (err) {
GenerateWarning("Driver error unexpected by WebGL: 0x%04x", err);
// This might be:
// - INVALID_OPERATION from ANGLE due to incomplete RBAB implementation for
// DrawElements
// with DYNAMIC_DRAW index buffer.
}
return err;
}
webgl::GetUniformData WebGLContext::GetUniform(const WebGLProgram& prog,
const uint32_t loc) const {
const FuncScope funcScope(*this, "getUniform");
webgl::GetUniformData ret;
[&]() {
if (IsContextLost()) return;
const auto& info = prog.LinkInfo();
if (!info) return;
const auto locInfo = MaybeFind(info->locationMap, loc);
if (!locInfo) return;
ret.type = locInfo->info.info.elemType;
switch (ret.type) {
case LOCAL_GL_FLOAT:
case LOCAL_GL_FLOAT_VEC2:
case LOCAL_GL_FLOAT_VEC3:
case LOCAL_GL_FLOAT_VEC4:
case LOCAL_GL_FLOAT_MAT2:
case LOCAL_GL_FLOAT_MAT3:
case LOCAL_GL_FLOAT_MAT4:
case LOCAL_GL_FLOAT_MAT2x3:
case LOCAL_GL_FLOAT_MAT2x4:
case LOCAL_GL_FLOAT_MAT3x2:
case LOCAL_GL_FLOAT_MAT3x4:
case LOCAL_GL_FLOAT_MAT4x2:
case LOCAL_GL_FLOAT_MAT4x3:
gl->fGetUniformfv(prog.mGLName, loc,
reinterpret_cast<float*>(ret.data));
break;
case LOCAL_GL_INT:
case LOCAL_GL_INT_VEC2:
case LOCAL_GL_INT_VEC3:
case LOCAL_GL_INT_VEC4:
case LOCAL_GL_SAMPLER_2D:
case LOCAL_GL_SAMPLER_3D:
case LOCAL_GL_SAMPLER_CUBE:
case LOCAL_GL_SAMPLER_2D_SHADOW:
case LOCAL_GL_SAMPLER_2D_ARRAY:
case LOCAL_GL_SAMPLER_2D_ARRAY_SHADOW:
case LOCAL_GL_SAMPLER_CUBE_SHADOW:
case LOCAL_GL_INT_SAMPLER_2D:
case LOCAL_GL_INT_SAMPLER_3D:
case LOCAL_GL_INT_SAMPLER_CUBE:
case LOCAL_GL_INT_SAMPLER_2D_ARRAY:
case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D:
case LOCAL_GL_UNSIGNED_INT_SAMPLER_3D:
case LOCAL_GL_UNSIGNED_INT_SAMPLER_CUBE:
case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
case LOCAL_GL_BOOL:
case LOCAL_GL_BOOL_VEC2:
case LOCAL_GL_BOOL_VEC3:
case LOCAL_GL_BOOL_VEC4:
gl->fGetUniformiv(prog.mGLName, loc,
reinterpret_cast<int32_t*>(ret.data));
break;
case LOCAL_GL_UNSIGNED_INT:
case LOCAL_GL_UNSIGNED_INT_VEC2:
case LOCAL_GL_UNSIGNED_INT_VEC3:
case LOCAL_GL_UNSIGNED_INT_VEC4:
gl->fGetUniformuiv(prog.mGLName, loc,
reinterpret_cast<uint32_t*>(ret.data));
break;
default:
MOZ_CRASH("GFX: Invalid elemType.");
}
}();
return ret;
}
void WebGLContext::Hint(GLenum target, GLenum mode) {
const FuncScope funcScope(*this, "hint");
if (IsContextLost()) return;
bool isValid = false;
switch (target) {
case LOCAL_GL_GENERATE_MIPMAP_HINT:
mGenerateMipmapHint = mode;
isValid = true;
// Deprecated and removed in desktop GL Core profiles.
if (gl->IsCoreProfile()) return;
break;
case LOCAL_GL_FRAGMENT_SHADER_DERIVATIVE_HINT:
if (IsWebGL2() ||
IsExtensionEnabled(WebGLExtensionID::OES_standard_derivatives)) {
isValid = true;
}
break;
}
if (!isValid) return ErrorInvalidEnumInfo("target", target);
gl->fHint(target, mode);
}
// -
void WebGLContext::LinkProgram(WebGLProgram& prog) {
const FuncScope funcScope(*this, "linkProgram");
if (IsContextLost()) return;
prog.LinkProgram();
if (!prog.IsLinked()) {
// If we failed to link, but `prog == mCurrentProgram`, we are *not*
// supposed to null out mActiveProgramLinkInfo.
return;
}
if (&prog == mCurrentProgram) {
mActiveProgramLinkInfo = prog.LinkInfo();
if (gl->WorkAroundDriverBugs() && gl->Vendor() == gl::GLVendor::NVIDIA) {
gl->fUseProgram(prog.mGLName);
}
}
}
void WebGLContext::PixelStorei(GLenum pname, GLint param) {
const FuncScope funcScope(*this, "pixelStorei");
if (IsContextLost()) return;
if (IsWebGL2()) {
uint32_t* pValueSlot = nullptr;
switch (pname) {
case LOCAL_GL_UNPACK_IMAGE_HEIGHT:
pValueSlot = &mPixelStore.mUnpackImageHeight;
break;
case LOCAL_GL_UNPACK_SKIP_IMAGES:
pValueSlot = &mPixelStore.mUnpackSkipImages;
break;
case LOCAL_GL_UNPACK_ROW_LENGTH:
pValueSlot = &mPixelStore.mUnpackRowLength;
break;
case LOCAL_GL_UNPACK_SKIP_ROWS:
pValueSlot = &mPixelStore.mUnpackSkipRows;
break;
case LOCAL_GL_UNPACK_SKIP_PIXELS:
pValueSlot = &mPixelStore.mUnpackSkipPixels;
break;
case LOCAL_GL_PACK_ROW_LENGTH:
pValueSlot = &mPixelStore.mPackRowLength;
break;
case LOCAL_GL_PACK_SKIP_ROWS:
pValueSlot = &mPixelStore.mPackSkipRows;
break;
case LOCAL_GL_PACK_SKIP_PIXELS:
pValueSlot = &mPixelStore.mPackSkipPixels;
break;
}
if (pValueSlot) {
if (!ValidateNonNegative("param", param)) return;
gl->fPixelStorei(pname, param);
*pValueSlot = param;
return;
}
}
switch (pname) {
case UNPACK_FLIP_Y_WEBGL:
mPixelStore.mFlipY = bool(param);
return;
case UNPACK_PREMULTIPLY_ALPHA_WEBGL:
mPixelStore.mPremultiplyAlpha = bool(param);
return;
case UNPACK_COLORSPACE_CONVERSION_WEBGL:
switch (param) {
case LOCAL_GL_NONE:
case BROWSER_DEFAULT_WEBGL:
mPixelStore.mColorspaceConversion = param;
return;
default:
ErrorInvalidEnumInfo("colorspace conversion parameter", param);
return;
}
case UNPACK_REQUIRE_FASTPATH:
if (IsExtensionEnabled(WebGLExtensionID::MOZ_debug)) {
mPixelStore.mRequireFastPath = bool(param);
return;
}
break;
case LOCAL_GL_PACK_ALIGNMENT:
case LOCAL_GL_UNPACK_ALIGNMENT:
switch (param) {
case 1:
case 2:
case 4:
case 8:
if (pname == LOCAL_GL_PACK_ALIGNMENT)
mPixelStore.mPackAlignment = param;
else if (pname == LOCAL_GL_UNPACK_ALIGNMENT)
mPixelStore.mUnpackAlignment = param;
gl->fPixelStorei(pname, param);
return;
default:
ErrorInvalidValue("Invalid pack/unpack alignment value.");
return;
}
default:
break;
}
ErrorInvalidEnumInfo("pname", pname);
return;
}
bool WebGLContext::DoReadPixelsAndConvert(const webgl::FormatInfo* srcFormat,
GLint x, GLint y, GLsizei width,
GLsizei height, GLenum format,
GLenum destType, uintptr_t dest,
uint64_t destSize,
uint32_t rowStride) {
// On at least Win+NV, we'll get PBO errors if we don't have at least
// `rowStride * height` bytes available to read into.
const auto naiveBytesNeeded = CheckedInt<uint64_t>(rowStride) * height;
const bool isDangerCloseToEdge =
(!naiveBytesNeeded.isValid() || naiveBytesNeeded.value() > destSize);
const bool useParanoidHandling =
(gl->WorkAroundDriverBugs() && isDangerCloseToEdge &&
mBoundPixelPackBuffer);
if (!useParanoidHandling) {
gl->fReadPixels(x, y, width, height, format, destType,
reinterpret_cast<void*>(dest));
return true;
}
// Read everything but the last row.
const auto bodyHeight = height - 1;
if (bodyHeight) {
gl->fReadPixels(x, y, width, bodyHeight, format, destType,
reinterpret_cast<void*>(dest));
}
// Now read the last row.
gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, 1);
gl->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH, 0);
gl->fPixelStorei(LOCAL_GL_PACK_SKIP_ROWS, 0);
const auto tailRowOffset = (char*)dest + rowStride * bodyHeight;
gl->fReadPixels(x, y + bodyHeight, width, 1, format, destType, tailRowOffset);
gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, mPixelStore.mPackAlignment);
gl->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH, mPixelStore.mPackRowLength);
gl->fPixelStorei(LOCAL_GL_PACK_SKIP_ROWS, mPixelStore.mPackSkipRows);
return true;
}
bool WebGLContext::ValidatePackSize(uint32_t width, uint32_t height,
uint8_t bytesPerPixel,
uint32_t* const out_rowStride,
uint32_t* const out_endOffset) {
if (!width || !height) {
*out_rowStride = 0;
*out_endOffset = 0;
return true;
}
// GLES 3.0.4, p116 (PACK_ functions like UNPACK_)
const auto rowLength =
(mPixelStore.mPackRowLength ? mPixelStore.mPackRowLength : width);
const auto skipPixels = mPixelStore.mPackSkipPixels;
const auto skipRows = mPixelStore.mPackSkipRows;
const auto alignment = mPixelStore.mPackAlignment;
const auto usedPixelsPerRow = CheckedUint32(skipPixels) + width;
const auto usedRowsPerImage = CheckedUint32(skipRows) + height;
if (!usedPixelsPerRow.isValid() || usedPixelsPerRow.value() > rowLength) {
ErrorInvalidOperation("SKIP_PIXELS + width > ROW_LENGTH.");
return false;
}
const auto rowLengthBytes = CheckedUint32(rowLength) * bytesPerPixel;
const auto rowStride = RoundUpToMultipleOf(rowLengthBytes, alignment);
const auto usedBytesPerRow = usedPixelsPerRow * bytesPerPixel;
const auto usedBytesPerImage =
(usedRowsPerImage - 1) * rowStride + usedBytesPerRow;
if (!rowStride.isValid() || !usedBytesPerImage.isValid()) {
ErrorInvalidOperation("Invalid UNPACK_ params.");
return false;
}
*out_rowStride = rowStride.value();
*out_endOffset = usedBytesPerImage.value();
return true;
}
void WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
GLenum format, GLenum type,
const Range<uint8_t>& dest) {
const FuncScope funcScope(*this, "readPixels");
if (IsContextLost()) return;
if (mBoundPixelPackBuffer) {
ErrorInvalidOperation("PIXEL_PACK_BUFFER must be null.");
return;
}
ReadPixelsImpl(x, y, width, height, format, type,
reinterpret_cast<uintptr_t>(dest.begin().get()),
dest.length());
}
void WebGLContext::ReadPixelsPbo(GLint x, GLint y, GLsizei width,
GLsizei height, GLenum format, GLenum type,
uint64_t offset) {
const FuncScope funcScope(*this, "readPixels");
if (IsContextLost()) return;
const auto& buffer = ValidateBufferSelection(LOCAL_GL_PIXEL_PACK_BUFFER);
if (!buffer) return;
//////
{
const auto bytesPerType = webgl::BytesPerPixel({LOCAL_GL_RED, type});
if (offset % bytesPerType != 0) {
ErrorInvalidOperation(
"`offset` must be divisible by the size of `type`"
" in bytes.");
return;
}
}
//////
auto bytesAvailable = buffer->ByteLength();
if (offset > bytesAvailable) {
ErrorInvalidOperation("`offset` too large for bound PIXEL_PACK_BUFFER.");
return;
}
bytesAvailable -= offset;
// -
const ScopedLazyBind lazyBind(gl, LOCAL_GL_PIXEL_PACK_BUFFER, buffer);
ReadPixelsImpl(x, y, width, height, format, type, offset, bytesAvailable);
buffer->ResetLastUpdateFenceId();
}
static webgl::PackingInfo DefaultReadPixelPI(
const webgl::FormatUsageInfo* usage) {
MOZ_ASSERT(usage->IsRenderable());
switch (usage->format->componentType) {
case webgl::ComponentType::NormUInt:
return {LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE};
case webgl::ComponentType::Int:
return {LOCAL_GL_RGBA_INTEGER, LOCAL_GL_INT};
case webgl::ComponentType::UInt:
return {LOCAL_GL_RGBA_INTEGER, LOCAL_GL_UNSIGNED_INT};
case webgl::ComponentType::Float:
return {LOCAL_GL_RGBA, LOCAL_GL_FLOAT};
default:
MOZ_CRASH();
}
}
static bool ArePossiblePackEnums(const WebGLContext* webgl,
const webgl::PackingInfo& pi) {
// OpenGL ES 2.0 $4.3.1 - IMPLEMENTATION_COLOR_READ_{TYPE/FORMAT} is a valid
// combination for glReadPixels()...
// Only valid when pulled from:
// * GLES 2.0.25 p105:
// "table 3.4, excluding formats LUMINANCE and LUMINANCE_ALPHA."
// * GLES 3.0.4 p193:
// "table 3.2, excluding formats DEPTH_COMPONENT and DEPTH_STENCIL."
switch (pi.format) {
case LOCAL_GL_LUMINANCE:
case LOCAL_GL_LUMINANCE_ALPHA:
case LOCAL_GL_DEPTH_COMPONENT:
case LOCAL_GL_DEPTH_STENCIL:
return false;
}
if (pi.type == LOCAL_GL_UNSIGNED_INT_24_8) return false;
uint8_t bytes;
if (!GetBytesPerPixel(pi, &bytes)) return false;
return true;
}
webgl::PackingInfo WebGLContext::ValidImplementationColorReadPI(
const webgl::FormatUsageInfo* usage) const {
const auto defaultPI = DefaultReadPixelPI(usage);
// ES2_compatibility always returns RGBA/UNSIGNED_BYTE, so branch on actual
// IsGLES(). Also OSX+NV generates an error here.
if (!gl->IsGLES()) return defaultPI;
webgl::PackingInfo implPI;
gl->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT,
(GLint*)&implPI.format);
gl->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE,
(GLint*)&implPI.type);
if (!ArePossiblePackEnums(this, implPI)) return defaultPI;
return implPI;
}
static bool ValidateReadPixelsFormatAndType(
const webgl::FormatUsageInfo* srcUsage, const webgl::PackingInfo& pi,
gl::GLContext* gl, WebGLContext* webgl) {
if (!ArePossiblePackEnums(webgl, pi)) {
webgl->ErrorInvalidEnum("Unexpected format or type.");
return false;
}
const auto defaultPI = DefaultReadPixelPI(srcUsage);
if (pi == defaultPI) return true;
////
// OpenGL ES 3.0.4 p194 - When the internal format of the rendering surface is
// RGB10_A2, a third combination of format RGBA and type
// UNSIGNED_INT_2_10_10_10_REV is accepted.
if (webgl->IsWebGL2() &&
srcUsage->format->effectiveFormat == webgl::EffectiveFormat::RGB10_A2 &&
pi.format == LOCAL_GL_RGBA &&
pi.type == LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV) {
return true;
}
////
MOZ_ASSERT(gl->IsCurrent());
const auto implPI = webgl->ValidImplementationColorReadPI(srcUsage);
if (pi == implPI) return true;
////
webgl->ErrorInvalidOperation("Incompatible format or type.");
return false;
}
void WebGLContext::ReadPixelsImpl(GLint x, GLint y, GLsizei rawWidth,
GLsizei rawHeight, GLenum packFormat,
GLenum packType, uintptr_t dest,
uint64_t availBytes) {
if (!ValidateNonNegative("width", rawWidth) ||
!ValidateNonNegative("height", rawHeight)) {
return;
}
const uint32_t width(rawWidth);
const uint32_t height(rawHeight);
//////
const webgl::FormatUsageInfo* srcFormat;
uint32_t srcWidth;
uint32_t srcHeight;
if (!BindCurFBForColorRead(&srcFormat, &srcWidth, &srcHeight)) return;
//////
const webgl::PackingInfo pi = {packFormat, packType};
if (!ValidateReadPixelsFormatAndType(srcFormat, pi, gl, this)) return;
uint8_t bytesPerPixel;
if (!webgl::GetBytesPerPixel(pi, &bytesPerPixel)) {
ErrorInvalidOperation("Unsupported format and type.");
return;
}
//////
uint32_t rowStride;
uint32_t bytesNeeded;
if (!ValidatePackSize(width, height, bytesPerPixel, &rowStride, &bytesNeeded))
return;
if (bytesNeeded > availBytes) {
ErrorInvalidOperation("buffer too small");
return;
}
////
int32_t readX, readY;
int32_t writeX, writeY;
int32_t rwWidth, rwHeight;
if (!Intersect(srcWidth, x, width, &readX, &writeX, &rwWidth) ||
!Intersect(srcHeight, y, height, &readY, &writeY, &rwHeight)) {
ErrorOutOfMemory("Bad subrect selection.");
return;
}
////////////////
// Now that the errors are out of the way, on to actually reading!
if (!rwWidth || !rwHeight) {
// Disjoint rects, so we're done already.
DummyReadFramebufferOperation();
return;
}
if (uint32_t(rwWidth) == width && uint32_t(rwHeight) == height) {
DoReadPixelsAndConvert(srcFormat->format, x, y, width, height, packFormat,
packType, dest, bytesNeeded, rowStride);
return;
}
// Read request contains out-of-bounds pixels. Unfortunately:
// GLES 3.0.4 p194 "Obtaining Pixels from the Framebuffer":
// "If any of these pixels lies outside of the window allocated to the current
// GL context, or outside of the image attached to the currently bound
// framebuffer object, then the values obtained for those pixels are
// undefined."
// This is a slow-path, so warn people away!
GenerateWarning(
"Out-of-bounds reads with readPixels are deprecated, and"
" may be slow.");
////////////////////////////////////
// Read only the in-bounds pixels.
if (IsWebGL2()) {
if (!mPixelStore.mPackRowLength) {
gl->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH,
mPixelStore.mPackSkipPixels + width);
}
gl->fPixelStorei(LOCAL_GL_PACK_SKIP_PIXELS,
mPixelStore.mPackSkipPixels + writeX);
gl->fPixelStorei(LOCAL_GL_PACK_SKIP_ROWS,
mPixelStore.mPackSkipRows + writeY);
DoReadPixelsAndConvert(srcFormat->format, readX, readY, rwWidth, rwHeight,
packFormat, packType, dest, bytesNeeded, rowStride);
gl->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH, mPixelStore.mPackRowLength);
gl->fPixelStorei(LOCAL_GL_PACK_SKIP_PIXELS, mPixelStore.mPackSkipPixels);
gl->fPixelStorei(LOCAL_GL_PACK_SKIP_ROWS, mPixelStore.mPackSkipRows);
} else {
// I *did* say "hilariously slow".
auto row = dest + writeX * bytesPerPixel;
row += writeY * rowStride;
for (uint32_t j = 0; j < uint32_t(rwHeight); j++) {
DoReadPixelsAndConvert(srcFormat->format, readX, readY + j, rwWidth, 1,
packFormat, packType, row, bytesNeeded, rowStride);
row += rowStride;
}
}
}
void WebGLContext::RenderbufferStorageMultisample(WebGLRenderbuffer& rb,
uint32_t samples,
GLenum internalFormat,
uint32_t width,
uint32_t height) const {
const FuncScope funcScope(*this, "renderbufferStorage(Multisample)?");
if (IsContextLost()) return;
rb.RenderbufferStorage(samples, internalFormat, width, height);
}
void WebGLContext::Scissor(GLint x, GLint y, GLsizei width, GLsizei height) {
const FuncScope funcScope(*this, "scissor");
if (IsContextLost()) return;
if (!ValidateNonNegative("width", width) ||
!ValidateNonNegative("height", height)) {
return;
}
mScissorRect = {x, y, width, height};
mScissorRect.Apply(*gl);
}
void WebGLContext::StencilFuncSeparate(GLenum face, GLenum func, GLint ref,
GLuint mask) {
const FuncScope funcScope(*this, "stencilFuncSeparate");
if (IsContextLost()) return;
if (!ValidateFaceEnum(face) || !ValidateComparisonEnum(*this, func)) {
return;
}
switch (face) {
case LOCAL_GL_FRONT_AND_BACK:
mStencilRefFront = ref;
mStencilRefBack = ref;
mStencilValueMaskFront = mask;
mStencilValueMaskBack = mask;
break;
case LOCAL_GL_FRONT:
mStencilRefFront = ref;
mStencilValueMaskFront = mask;
break;
case LOCAL_GL_BACK:
mStencilRefBack = ref;
mStencilValueMaskBack = mask;
break;
}
gl->fStencilFuncSeparate(face, func, ref, mask);
}
void WebGLContext::StencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail,
GLenum dppass) {
const FuncScope funcScope(*this, "stencilOpSeparate");
if (IsContextLost()) return;
if (!ValidateFaceEnum(face) || !ValidateStencilOpEnum(sfail, "sfail") ||
!ValidateStencilOpEnum(dpfail, "dpfail") ||
!ValidateStencilOpEnum(dppass, "dppass"))
return;
gl->fStencilOpSeparate(face, sfail, dpfail, dppass);
}
////////////////////////////////////////////////////////////////////////////////
// Uniform setters.
void WebGLContext::UniformData(const uint32_t loc, const bool transpose,
const Range<const uint8_t>& data) const {
const FuncScope funcScope(*this, "uniform setter");
const auto& link = mActiveProgramLinkInfo;
if (!link) return;
const auto locInfo = MaybeFind(link->locationMap, loc);
if (!locInfo) return;
const auto& validationInfo = locInfo->info;
Bug 1477756 - Fix all webgl regression tests according to CI. r=handyman (This is a combination of 31 commits) * Fix Linux compilation. * Fix mac compilation. * CI compile fixes. * printf's size_t is %zu. %tu would be unsigned ptrdiff_t. * No non-ref Maybe args. * MOZ_CRASH for noreturn * Handle implied texture sizes, rewrite comment stripping. * Replace e.g. WebGLProgramInner with simpler webgl::ProgramKeepAlive. * Bounce ValidateProgram call off driver. * Uniform name length limit, cubemap fb-attach, non-array uniforms, undersized texImage views. * alignas for uint8_t[sizeof(float)*N] pun buffers. * CC fixes? * Fill attrib0Active. * Repair max-warnings limit. * This is basically required in order for CI's logging to not explode. * Don't cache WebGLMemoryTracker. * Deleted prog/shader error, no texSubImage(null), client-side fingerprint resist for exts. * Fix GetUniformIndices and MakeRangeFromView. * CC Traverse base class from within derived class to fix leaking the world. :( * PauseTransformFeedback * TexImage video fastpath * GetFragLocation for arrays * Forbid BindBufferRange during TF * Mark tests and fix RBAB query and test. * Change(!) query deletion behavior to match spec. * Mark conformance2/query/query.html failing for now. * Implicitly EndQuery on DeleteQuery while spec is in flux. * Fix error code for test. * RAII LruPosition for WebGL context limit. * Include std::list. * Mark CompileResult and LinkResult.pending as false when retrieved. * Hold strong-ref to NotLostData during Run<> to prevent LoseContext=>UAF. * Don't assume GetUniformLocation(foo+'[0]') means foo is an array. * Don't assume !mCanvasElement means !!mOffscreenCanvas. * Handle composition while context-lost. * All non-value-init members must be const or have inline init. * Mark passing tests on Linux. Depends on D54019 Differential Revision: https://phabricator.services.mozilla.com/D55739 --HG-- extra : moz-landing-system : lando
2020-01-09 01:19:23 +03:00
const auto& activeInfo = validationInfo.info;
const auto& channels = validationInfo.channelsPerElem;
const auto& pfn = validationInfo.pfn;
// -
const auto lengthInType = data.length() / sizeof(float);
if (!lengthInType || lengthInType % channels != 0) {
GenerateError(LOCAL_GL_INVALID_VALUE,
Bug 1477756 - Fix all webgl regression tests according to CI. r=handyman (This is a combination of 31 commits) * Fix Linux compilation. * Fix mac compilation. * CI compile fixes. * printf's size_t is %zu. %tu would be unsigned ptrdiff_t. * No non-ref Maybe args. * MOZ_CRASH for noreturn * Handle implied texture sizes, rewrite comment stripping. * Replace e.g. WebGLProgramInner with simpler webgl::ProgramKeepAlive. * Bounce ValidateProgram call off driver. * Uniform name length limit, cubemap fb-attach, non-array uniforms, undersized texImage views. * alignas for uint8_t[sizeof(float)*N] pun buffers. * CC fixes? * Fill attrib0Active. * Repair max-warnings limit. * This is basically required in order for CI's logging to not explode. * Don't cache WebGLMemoryTracker. * Deleted prog/shader error, no texSubImage(null), client-side fingerprint resist for exts. * Fix GetUniformIndices and MakeRangeFromView. * CC Traverse base class from within derived class to fix leaking the world. :( * PauseTransformFeedback * TexImage video fastpath * GetFragLocation for arrays * Forbid BindBufferRange during TF * Mark tests and fix RBAB query and test. * Change(!) query deletion behavior to match spec. * Mark conformance2/query/query.html failing for now. * Implicitly EndQuery on DeleteQuery while spec is in flux. * Fix error code for test. * RAII LruPosition for WebGL context limit. * Include std::list. * Mark CompileResult and LinkResult.pending as false when retrieved. * Hold strong-ref to NotLostData during Run<> to prevent LoseContext=>UAF. * Don't assume GetUniformLocation(foo+'[0]') means foo is an array. * Don't assume !mCanvasElement means !!mOffscreenCanvas. * Handle composition while context-lost. * All non-value-init members must be const or have inline init. * Mark passing tests on Linux. Depends on D54019 Differential Revision: https://phabricator.services.mozilla.com/D55739 --HG-- extra : moz-landing-system : lando
2020-01-09 01:19:23 +03:00
"(uniform %s) `values` length (%u) must be a positive "
"integer multiple of "
"size of %s.",
Bug 1477756 - Fix all webgl regression tests according to CI. r=handyman (This is a combination of 31 commits) * Fix Linux compilation. * Fix mac compilation. * CI compile fixes. * printf's size_t is %zu. %tu would be unsigned ptrdiff_t. * No non-ref Maybe args. * MOZ_CRASH for noreturn * Handle implied texture sizes, rewrite comment stripping. * Replace e.g. WebGLProgramInner with simpler webgl::ProgramKeepAlive. * Bounce ValidateProgram call off driver. * Uniform name length limit, cubemap fb-attach, non-array uniforms, undersized texImage views. * alignas for uint8_t[sizeof(float)*N] pun buffers. * CC fixes? * Fill attrib0Active. * Repair max-warnings limit. * This is basically required in order for CI's logging to not explode. * Don't cache WebGLMemoryTracker. * Deleted prog/shader error, no texSubImage(null), client-side fingerprint resist for exts. * Fix GetUniformIndices and MakeRangeFromView. * CC Traverse base class from within derived class to fix leaking the world. :( * PauseTransformFeedback * TexImage video fastpath * GetFragLocation for arrays * Forbid BindBufferRange during TF * Mark tests and fix RBAB query and test. * Change(!) query deletion behavior to match spec. * Mark conformance2/query/query.html failing for now. * Implicitly EndQuery on DeleteQuery while spec is in flux. * Fix error code for test. * RAII LruPosition for WebGL context limit. * Include std::list. * Mark CompileResult and LinkResult.pending as false when retrieved. * Hold strong-ref to NotLostData during Run<> to prevent LoseContext=>UAF. * Don't assume GetUniformLocation(foo+'[0]') means foo is an array. * Don't assume !mCanvasElement means !!mOffscreenCanvas. * Handle composition while context-lost. * All non-value-init members must be const or have inline init. * Mark passing tests on Linux. Depends on D54019 Differential Revision: https://phabricator.services.mozilla.com/D55739 --HG-- extra : moz-landing-system : lando
2020-01-09 01:19:23 +03:00
activeInfo.name.c_str(), lengthInType,
EnumString(activeInfo.elemType).c_str());
return;
}
const auto elemCount = lengthInType / channels;
Bug 1477756 - Fix all webgl regression tests according to CI. r=handyman (This is a combination of 31 commits) * Fix Linux compilation. * Fix mac compilation. * CI compile fixes. * printf's size_t is %zu. %tu would be unsigned ptrdiff_t. * No non-ref Maybe args. * MOZ_CRASH for noreturn * Handle implied texture sizes, rewrite comment stripping. * Replace e.g. WebGLProgramInner with simpler webgl::ProgramKeepAlive. * Bounce ValidateProgram call off driver. * Uniform name length limit, cubemap fb-attach, non-array uniforms, undersized texImage views. * alignas for uint8_t[sizeof(float)*N] pun buffers. * CC fixes? * Fill attrib0Active. * Repair max-warnings limit. * This is basically required in order for CI's logging to not explode. * Don't cache WebGLMemoryTracker. * Deleted prog/shader error, no texSubImage(null), client-side fingerprint resist for exts. * Fix GetUniformIndices and MakeRangeFromView. * CC Traverse base class from within derived class to fix leaking the world. :( * PauseTransformFeedback * TexImage video fastpath * GetFragLocation for arrays * Forbid BindBufferRange during TF * Mark tests and fix RBAB query and test. * Change(!) query deletion behavior to match spec. * Mark conformance2/query/query.html failing for now. * Implicitly EndQuery on DeleteQuery while spec is in flux. * Fix error code for test. * RAII LruPosition for WebGL context limit. * Include std::list. * Mark CompileResult and LinkResult.pending as false when retrieved. * Hold strong-ref to NotLostData during Run<> to prevent LoseContext=>UAF. * Don't assume GetUniformLocation(foo+'[0]') means foo is an array. * Don't assume !mCanvasElement means !!mOffscreenCanvas. * Handle composition while context-lost. * All non-value-init members must be const or have inline init. * Mark passing tests on Linux. Depends on D54019 Differential Revision: https://phabricator.services.mozilla.com/D55739 --HG-- extra : moz-landing-system : lando
2020-01-09 01:19:23 +03:00
if (elemCount > 1 && !validationInfo.isArray) {
GenerateError(
LOCAL_GL_INVALID_OPERATION,
"(uniform %s) `values` length (%u) must exactle match size of %s.",
activeInfo.name.c_str(), lengthInType,
EnumString(activeInfo.elemType).c_str());
return;
}
// -
const auto& samplerInfo = locInfo->samplerInfo;
if (samplerInfo) {
const auto idata = reinterpret_cast<const uint32_t*>(data.begin().get());
const auto maxTexUnits = GLMaxTextureUnits();
for (const auto& val : Range<const uint32_t>(idata, elemCount)) {
if (val >= maxTexUnits) {
ErrorInvalidValue(
"This uniform location is a sampler, but %d"
" is not a valid texture unit.",
val);
return;
}
}
}
// -
// This is a little galaxy-brain, sorry!
const auto ptr = static_cast<const void*>(data.begin().get());
(*pfn)(*gl, static_cast<GLint>(loc), elemCount, transpose, ptr);
// -
if (samplerInfo) {
auto& texUnits = samplerInfo->texUnits;
const auto srcBegin = reinterpret_cast<const uint32_t*>(data.begin().get());
auto destIndex = locInfo->indexIntoUniform;
for (const auto& val : Range<const uint32_t>(srcBegin, elemCount)) {
if (destIndex >= texUnits.size()) break;
texUnits[destIndex] = val;
destIndex += 1;
}
}
}
////////////////////////////////////////////////////////////////////////////////
void WebGLContext::UseProgram(WebGLProgram* prog) {
FuncScope funcScope(*this, "useProgram");
if (IsContextLost()) return;
funcScope.mBindFailureGuard = true;
if (!prog) {
mCurrentProgram = nullptr;
mActiveProgramLinkInfo = nullptr;
funcScope.mBindFailureGuard = false;
return;
}
if (!ValidateObject("prog", *prog)) return;
if (!prog->UseProgram()) return;
mCurrentProgram = prog;
mActiveProgramLinkInfo = mCurrentProgram->LinkInfo();
funcScope.mBindFailureGuard = false;
}
Bug 1477756 - Fix all webgl regression tests according to CI. r=handyman (This is a combination of 31 commits) * Fix Linux compilation. * Fix mac compilation. * CI compile fixes. * printf's size_t is %zu. %tu would be unsigned ptrdiff_t. * No non-ref Maybe args. * MOZ_CRASH for noreturn * Handle implied texture sizes, rewrite comment stripping. * Replace e.g. WebGLProgramInner with simpler webgl::ProgramKeepAlive. * Bounce ValidateProgram call off driver. * Uniform name length limit, cubemap fb-attach, non-array uniforms, undersized texImage views. * alignas for uint8_t[sizeof(float)*N] pun buffers. * CC fixes? * Fill attrib0Active. * Repair max-warnings limit. * This is basically required in order for CI's logging to not explode. * Don't cache WebGLMemoryTracker. * Deleted prog/shader error, no texSubImage(null), client-side fingerprint resist for exts. * Fix GetUniformIndices and MakeRangeFromView. * CC Traverse base class from within derived class to fix leaking the world. :( * PauseTransformFeedback * TexImage video fastpath * GetFragLocation for arrays * Forbid BindBufferRange during TF * Mark tests and fix RBAB query and test. * Change(!) query deletion behavior to match spec. * Mark conformance2/query/query.html failing for now. * Implicitly EndQuery on DeleteQuery while spec is in flux. * Fix error code for test. * RAII LruPosition for WebGL context limit. * Include std::list. * Mark CompileResult and LinkResult.pending as false when retrieved. * Hold strong-ref to NotLostData during Run<> to prevent LoseContext=>UAF. * Don't assume GetUniformLocation(foo+'[0]') means foo is an array. * Don't assume !mCanvasElement means !!mOffscreenCanvas. * Handle composition while context-lost. * All non-value-init members must be const or have inline init. * Mark passing tests on Linux. Depends on D54019 Differential Revision: https://phabricator.services.mozilla.com/D55739 --HG-- extra : moz-landing-system : lando
2020-01-09 01:19:23 +03:00
bool WebGLContext::ValidateProgram(const WebGLProgram& prog) const {
const FuncScope funcScope(*this, "validateProgram");
Bug 1477756 - Fix all webgl regression tests according to CI. r=handyman (This is a combination of 31 commits) * Fix Linux compilation. * Fix mac compilation. * CI compile fixes. * printf's size_t is %zu. %tu would be unsigned ptrdiff_t. * No non-ref Maybe args. * MOZ_CRASH for noreturn * Handle implied texture sizes, rewrite comment stripping. * Replace e.g. WebGLProgramInner with simpler webgl::ProgramKeepAlive. * Bounce ValidateProgram call off driver. * Uniform name length limit, cubemap fb-attach, non-array uniforms, undersized texImage views. * alignas for uint8_t[sizeof(float)*N] pun buffers. * CC fixes? * Fill attrib0Active. * Repair max-warnings limit. * This is basically required in order for CI's logging to not explode. * Don't cache WebGLMemoryTracker. * Deleted prog/shader error, no texSubImage(null), client-side fingerprint resist for exts. * Fix GetUniformIndices and MakeRangeFromView. * CC Traverse base class from within derived class to fix leaking the world. :( * PauseTransformFeedback * TexImage video fastpath * GetFragLocation for arrays * Forbid BindBufferRange during TF * Mark tests and fix RBAB query and test. * Change(!) query deletion behavior to match spec. * Mark conformance2/query/query.html failing for now. * Implicitly EndQuery on DeleteQuery while spec is in flux. * Fix error code for test. * RAII LruPosition for WebGL context limit. * Include std::list. * Mark CompileResult and LinkResult.pending as false when retrieved. * Hold strong-ref to NotLostData during Run<> to prevent LoseContext=>UAF. * Don't assume GetUniformLocation(foo+'[0]') means foo is an array. * Don't assume !mCanvasElement means !!mOffscreenCanvas. * Handle composition while context-lost. * All non-value-init members must be const or have inline init. * Mark passing tests on Linux. Depends on D54019 Differential Revision: https://phabricator.services.mozilla.com/D55739 --HG-- extra : moz-landing-system : lando
2020-01-09 01:19:23 +03:00
if (IsContextLost()) return false;
Bug 1477756 - Fix all webgl regression tests according to CI. r=handyman (This is a combination of 31 commits) * Fix Linux compilation. * Fix mac compilation. * CI compile fixes. * printf's size_t is %zu. %tu would be unsigned ptrdiff_t. * No non-ref Maybe args. * MOZ_CRASH for noreturn * Handle implied texture sizes, rewrite comment stripping. * Replace e.g. WebGLProgramInner with simpler webgl::ProgramKeepAlive. * Bounce ValidateProgram call off driver. * Uniform name length limit, cubemap fb-attach, non-array uniforms, undersized texImage views. * alignas for uint8_t[sizeof(float)*N] pun buffers. * CC fixes? * Fill attrib0Active. * Repair max-warnings limit. * This is basically required in order for CI's logging to not explode. * Don't cache WebGLMemoryTracker. * Deleted prog/shader error, no texSubImage(null), client-side fingerprint resist for exts. * Fix GetUniformIndices and MakeRangeFromView. * CC Traverse base class from within derived class to fix leaking the world. :( * PauseTransformFeedback * TexImage video fastpath * GetFragLocation for arrays * Forbid BindBufferRange during TF * Mark tests and fix RBAB query and test. * Change(!) query deletion behavior to match spec. * Mark conformance2/query/query.html failing for now. * Implicitly EndQuery on DeleteQuery while spec is in flux. * Fix error code for test. * RAII LruPosition for WebGL context limit. * Include std::list. * Mark CompileResult and LinkResult.pending as false when retrieved. * Hold strong-ref to NotLostData during Run<> to prevent LoseContext=>UAF. * Don't assume GetUniformLocation(foo+'[0]') means foo is an array. * Don't assume !mCanvasElement means !!mOffscreenCanvas. * Handle composition while context-lost. * All non-value-init members must be const or have inline init. * Mark passing tests on Linux. Depends on D54019 Differential Revision: https://phabricator.services.mozilla.com/D55739 --HG-- extra : moz-landing-system : lando
2020-01-09 01:19:23 +03:00
return prog.ValidateProgram();
}
RefPtr<WebGLFramebuffer> WebGLContext::CreateFramebuffer() {
const FuncScope funcScope(*this, "createFramebuffer");
if (IsContextLost()) return nullptr;
GLuint fbo = 0;
gl->fGenFramebuffers(1, &fbo);
return new WebGLFramebuffer(this, fbo);
}
RefPtr<WebGLRenderbuffer> WebGLContext::CreateRenderbuffer() {
const FuncScope funcScope(*this, "createRenderbuffer");
if (IsContextLost()) return nullptr;
return new WebGLRenderbuffer(this);
}
void WebGLContext::Viewport(GLint x, GLint y, GLsizei width, GLsizei height) {
const FuncScope funcScope(*this, "viewport");
if (IsContextLost()) return;
if (!ValidateNonNegative("width", width) ||
!ValidateNonNegative("height", height)) {
return;
}
const auto& limits = Limits();
width = std::min(width, static_cast<GLsizei>(limits.maxViewportDims[0]));
height = std::min(height, static_cast<GLsizei>(limits.maxViewportDims[1]));
gl->fViewport(x, y, width, height);
mViewportX = x;
mViewportY = y;
mViewportWidth = width;
mViewportHeight = height;
}
void WebGLContext::CompileShader(WebGLShader& shader) {
const FuncScope funcScope(*this, "compileShader");
if (IsContextLost()) return;
if (!ValidateObject("shader", shader)) return;
shader.CompileShader();
}
Maybe<webgl::ShaderPrecisionFormat> WebGLContext::GetShaderPrecisionFormat(
GLenum shadertype, GLenum precisiontype) const {
const FuncScope funcScope(*this, "getShaderPrecisionFormat");
if (IsContextLost()) return Nothing();
switch (shadertype) {
case LOCAL_GL_FRAGMENT_SHADER:
case LOCAL_GL_VERTEX_SHADER:
break;
default:
ErrorInvalidEnumInfo("shadertype", shadertype);
return Nothing();
}
switch (precisiontype) {
case LOCAL_GL_LOW_FLOAT:
case LOCAL_GL_MEDIUM_FLOAT:
case LOCAL_GL_HIGH_FLOAT:
case LOCAL_GL_LOW_INT:
case LOCAL_GL_MEDIUM_INT:
case LOCAL_GL_HIGH_INT:
break;
default:
ErrorInvalidEnumInfo("precisiontype", precisiontype);
return Nothing();
}
GLint range[2], precision;
if (mDisableFragHighP && shadertype == LOCAL_GL_FRAGMENT_SHADER &&
(precisiontype == LOCAL_GL_HIGH_FLOAT ||
precisiontype == LOCAL_GL_HIGH_INT)) {
precision = 0;
range[0] = 0;
range[1] = 0;
} else {
gl->fGetShaderPrecisionFormat(shadertype, precisiontype, range, &precision);
}
return Some(webgl::ShaderPrecisionFormat{range[0], range[1], precision});
}
void WebGLContext::ShaderSource(WebGLShader& shader,
const std::string& source) const {
const FuncScope funcScope(*this, "shaderSource");
if (IsContextLost()) return;
shader.ShaderSource(source);
}
void WebGLContext::BlendColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) {
const FuncScope funcScope(*this, "blendColor");
if (IsContextLost()) return;
gl->fBlendColor(r, g, b, a);
}
void WebGLContext::Flush() {
const FuncScope funcScope(*this, "flush");
if (IsContextLost()) return;
gl->fFlush();
}
void WebGLContext::Finish() {
const FuncScope funcScope(*this, "finish");
if (IsContextLost()) return;
gl->fFinish();
mCompletedFenceId = mNextFenceId;
mNextFenceId += 1;
}
void WebGLContext::LineWidth(GLfloat width) {
const FuncScope funcScope(*this, "lineWidth");
if (IsContextLost()) return;
// Doing it this way instead of `if (width <= 0.0)` handles NaNs.
const bool isValid = width > 0.0;
if (!isValid) {
ErrorInvalidValue("`width` must be positive and non-zero.");
return;
}
mLineWidth = width;
if (gl->IsCoreProfile() && width > 1.0) {
width = 1.0;
}
gl->fLineWidth(width);
}
void WebGLContext::PolygonOffset(GLfloat factor, GLfloat units) {
const FuncScope funcScope(*this, "polygonOffset");
if (IsContextLost()) return;
gl->fPolygonOffset(factor, units);
}
void WebGLContext::SampleCoverage(GLclampf value, WebGLboolean invert) {
const FuncScope funcScope(*this, "sampleCoverage");
if (IsContextLost()) return;
gl->fSampleCoverage(value, invert);
}
} // namespace mozilla