diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:47:29 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:47:29 +0000 |
commit | 0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d (patch) | |
tree | a31f07c9bcca9d56ce61e9a1ffd30ef350d513aa /dom/canvas/WebGLContextVertices.cpp | |
parent | Initial commit. (diff) | |
download | firefox-esr-upstream/115.8.0esr.tar.xz firefox-esr-upstream/115.8.0esr.zip |
Adding upstream version 115.8.0esr.upstream/115.8.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | dom/canvas/WebGLContextVertices.cpp | 305 |
1 files changed, 305 insertions, 0 deletions
diff --git a/dom/canvas/WebGLContextVertices.cpp b/dom/canvas/WebGLContextVertices.cpp new file mode 100644 index 0000000000..e50f5f1c3d --- /dev/null +++ b/dom/canvas/WebGLContextVertices.cpp @@ -0,0 +1,305 @@ +/* -*- 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 "GLContext.h" +#include "mozilla/Casting.h" +#include "mozilla/CheckedInt.h" +#include "WebGLBuffer.h" +#include "WebGLFramebuffer.h" +#include "WebGLProgram.h" +#include "WebGLRenderbuffer.h" +#include "WebGLShader.h" +#include "WebGLTexture.h" +#include "WebGLTypes.h" +#include "WebGLVertexArray.h" + +#include "mozilla/ResultVariant.h" + +namespace mozilla { + +static bool ValidateAttribIndex(WebGLContext& webgl, GLuint index) { + bool valid = (index < webgl.MaxVertexAttribs()); + + if (!valid) { + if (index == GLuint(-1)) { + webgl.ErrorInvalidValue( + "-1 is not a valid `index`. This value" + " probably comes from a getAttribLocation()" + " call, where this return value -1 means" + " that the passed name didn't correspond to" + " an active attribute in the specified" + " program."); + } else { + webgl.ErrorInvalidValue( + "`index` must be less than" + " MAX_VERTEX_ATTRIBS."); + } + } + + return valid; +} + +//////////////////////////////////////// + +void WebGLContext::VertexAttrib4T(GLuint index, const webgl::TypedQuad& src) { + const FuncScope funcScope(*this, "vertexAttrib[1234]u?[fi]v?"); + if (IsContextLost()) return; + + if (!ValidateAttribIndex(*this, index)) return; + + //// + + if (index || !gl->IsCompatibilityProfile()) { + switch (src.type) { + case webgl::AttribBaseType::Boolean: + case webgl::AttribBaseType::Float: + gl->fVertexAttrib4fv(index, + reinterpret_cast<const float*>(src.data.data())); + break; + case webgl::AttribBaseType::Int: + gl->fVertexAttribI4iv( + index, reinterpret_cast<const int32_t*>(src.data.data())); + break; + case webgl::AttribBaseType::Uint: + gl->fVertexAttribI4uiv( + index, reinterpret_cast<const uint32_t*>(src.data.data())); + break; + } + } + + //// + + mGenericVertexAttribTypes[index] = src.type; + mGenericVertexAttribTypeInvalidator.InvalidateCaches(); + + if (!index) { + memcpy(mGenericVertexAttrib0Data, src.data.data(), + sizeof(mGenericVertexAttrib0Data)); + } +} + +//////////////////////////////////////// + +void WebGLContext::EnableVertexAttribArray(GLuint index) { + const FuncScope funcScope(*this, "enableVertexAttribArray"); + if (IsContextLost()) return; + + if (!ValidateAttribIndex(*this, index)) return; + + gl->fEnableVertexAttribArray(index); + + MOZ_ASSERT(mBoundVertexArray); + mBoundVertexArray->SetAttribIsArray(index, true); +} + +void WebGLContext::DisableVertexAttribArray(GLuint index) { + const FuncScope funcScope(*this, "disableVertexAttribArray"); + if (IsContextLost()) return; + + if (!ValidateAttribIndex(*this, index)) return; + + if (index || !gl->IsCompatibilityProfile()) { + gl->fDisableVertexAttribArray(index); + } + + MOZ_ASSERT(mBoundVertexArray); + mBoundVertexArray->SetAttribIsArray(index, false); +} + +Maybe<double> WebGLContext::GetVertexAttrib(GLuint index, GLenum pname) { + const FuncScope funcScope(*this, "getVertexAttrib"); + if (IsContextLost()) return Nothing(); + + if (!ValidateAttribIndex(*this, index)) return Nothing(); + + MOZ_ASSERT(mBoundVertexArray); + auto ret = mBoundVertexArray->GetVertexAttrib(index, pname); + + switch (pname) { + case LOCAL_GL_VERTEX_ATTRIB_ARRAY_INTEGER: + if (!IsWebGL2()) { + ret = Nothing(); + } + break; + + case LOCAL_GL_VERTEX_ATTRIB_ARRAY_DIVISOR: + if (!IsWebGL2() && + !IsExtensionEnabled(WebGLExtensionID::ANGLE_instanced_arrays)) { + ret = Nothing(); + } + break; + } + + if (!ret) { + ErrorInvalidEnumInfo("pname", pname); + } + return ret; +} + +//////////////////////////////////////// + +Result<webgl::VertAttribPointerCalculated, webgl::ErrorInfo> +CheckVertexAttribPointer(const bool isWebgl2, + const webgl::VertAttribPointerDesc& desc) { + if (desc.channels < 1 || desc.channels > 4) { + return Err(webgl::ErrorInfo{LOCAL_GL_INVALID_VALUE, + "Channel count `size` must be within [1,4]."}); + } + + //// + + webgl::VertAttribPointerCalculated calc; + + bool isTypeValid = true; + bool isPackedType = false; + uint8_t bytesPerType = 0; + switch (desc.type) { + // WebGL 1: + case LOCAL_GL_BYTE: + bytesPerType = 1; + calc.baseType = webgl::AttribBaseType::Int; + break; + case LOCAL_GL_UNSIGNED_BYTE: + bytesPerType = 1; + calc.baseType = webgl::AttribBaseType::Uint; + break; + + case LOCAL_GL_SHORT: + bytesPerType = 2; + calc.baseType = webgl::AttribBaseType::Int; + break; + case LOCAL_GL_UNSIGNED_SHORT: + bytesPerType = 2; + calc.baseType = webgl::AttribBaseType::Uint; + break; + + case LOCAL_GL_FLOAT: + bytesPerType = 4; + calc.baseType = webgl::AttribBaseType::Float; + break; + + // WebGL 2: + case LOCAL_GL_INT: + isTypeValid = isWebgl2; + bytesPerType = 4; + calc.baseType = webgl::AttribBaseType::Int; + break; + case LOCAL_GL_UNSIGNED_INT: + isTypeValid = isWebgl2; + bytesPerType = 4; + calc.baseType = webgl::AttribBaseType::Uint; + break; + + case LOCAL_GL_HALF_FLOAT: + isTypeValid = isWebgl2; + bytesPerType = 2; + calc.baseType = webgl::AttribBaseType::Float; + break; + + case LOCAL_GL_INT_2_10_10_10_REV: + case LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV: + if (desc.channels != 4) { + return Err(webgl::ErrorInfo{LOCAL_GL_INVALID_OPERATION, + "Size must be 4 for this type."}); + } + isTypeValid = isWebgl2; + bytesPerType = 4; + calc.baseType = + webgl::AttribBaseType::Float; // Invalid for intFunc:true. + isPackedType = true; + break; + + default: + isTypeValid = false; + break; + } + if (desc.intFunc) { + isTypeValid = (calc.baseType != webgl::AttribBaseType::Float); + } else { + calc.baseType = webgl::AttribBaseType::Float; + } + if (!isTypeValid) { + const auto info = + nsPrintfCString("Bad `type`: %s", EnumString(desc.type).c_str()); + return Err(webgl::ErrorInfo{LOCAL_GL_INVALID_ENUM, info.BeginReading()}); + } + + //// + + calc.byteSize = bytesPerType; + if (!isPackedType) { + calc.byteSize *= desc.channels; + } + + calc.byteStride = + desc.byteStrideOrZero ? desc.byteStrideOrZero : calc.byteSize; + + // `alignment` should always be a power of two. + MOZ_ASSERT(IsPowerOfTwo(bytesPerType)); + const auto typeAlignmentMask = bytesPerType - 1; + + if (calc.byteStride & typeAlignmentMask || + desc.byteOffset & typeAlignmentMask) { + return Err( + webgl::ErrorInfo{LOCAL_GL_INVALID_OPERATION, + "`stride` and `byteOffset` must satisfy the alignment" + " requirement of `type`."}); + } + + return calc; +} + +void DoVertexAttribPointer(gl::GLContext& gl, const uint32_t index, + const webgl::VertAttribPointerDesc& desc) { + if (desc.intFunc) { + gl.fVertexAttribIPointer(index, desc.channels, desc.type, + desc.byteStrideOrZero, + reinterpret_cast<const void*>(desc.byteOffset)); + } else { + gl.fVertexAttribPointer(index, desc.channels, desc.type, desc.normalized, + desc.byteStrideOrZero, + reinterpret_cast<const void*>(desc.byteOffset)); + } +} + +void WebGLContext::VertexAttribPointer( + const uint32_t index, const webgl::VertAttribPointerDesc& desc) { + if (IsContextLost()) return; + if (!ValidateAttribIndex(*this, index)) return; + + const auto res = CheckVertexAttribPointer(IsWebGL2(), desc); + if (res.isErr()) { + const auto& err = res.inspectErr(); + GenerateError(err.type, "%s", err.info.c_str()); + return; + } + const auto& calc = res.inspect(); + + //// + + const auto& buffer = mBoundArrayBuffer; + + mBoundVertexArray->AttribPointer(index, buffer, desc, calc); + + const ScopedLazyBind lazyBind(gl, LOCAL_GL_ARRAY_BUFFER, buffer); + DoVertexAttribPointer(*gl, index, desc); +} + +//////////////////////////////////////// + +void WebGLContext::VertexAttribDivisor(GLuint index, GLuint divisor) { + const FuncScope funcScope(*this, "vertexAttribDivisor"); + if (IsContextLost()) return; + + if (!ValidateAttribIndex(*this, index)) return; + + MOZ_ASSERT(mBoundVertexArray); + mBoundVertexArray->AttribDivisor(index, divisor); + gl->fVertexAttribDivisor(index, divisor); +} + +} // namespace mozilla |