void WebGL2Context::GetActiveUniforms(WebGLProgram* program, const dom::Sequence<GLuint>& uniformIndices, GLenum pname, dom::Nullable< nsTArray<GLint> >& retval) { retval.SetNull(); if (IsContextLost()) return; if (pname == LOCAL_GL_UNIFORM_NAME_LENGTH) { ErrorInvalidEnumInfo("getActiveUniforms: pname", pname); return; } if (!ValidateObject("getActiveUniforms: program", program)) return; size_t count = uniformIndices.Length(); if (!count) return; GLuint progname = program->mGLName; nsTArray<GLint>& arr = retval.SetValue(); arr.SetLength(count); MakeContextCurrent(); gl->fGetActiveUniformsiv(progname, count, uniformIndices.Elements(), pname, arr.Elements()); }
void WebGLContext::GetSupportedExtensions(JSContext* cx, dom::Nullable< nsTArray<nsString> >& retval) { retval.SetNull(); if (IsContextLost()) return; nsTArray<nsString>& arr = retval.SetValue(); for (size_t i = 0; i < size_t(WebGLExtensionID::Max); i++) { WebGLExtensionID extension = WebGLExtensionID(i); if (IsExtensionSupported(cx, extension)) { const char* extStr = GetExtensionString(extension); arr.AppendElement(NS_ConvertUTF8toUTF16(extStr)); } } /** * We keep backward compatibility for these deprecated vendor-prefixed * alias. Do not add new ones anymore. Hide it behind the * webgl.enable-draft-extensions flag instead. */ if (IsExtensionSupported(cx, WebGLExtensionID::WEBGL_lose_context)) arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_lose_context")); if (IsExtensionSupported(cx, WebGLExtensionID::WEBGL_compressed_texture_s3tc)) arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_compressed_texture_s3tc")); if (IsExtensionSupported(cx, WebGLExtensionID::WEBGL_compressed_texture_atc)) arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_compressed_texture_atc")); if (IsExtensionSupported(cx, WebGLExtensionID::WEBGL_compressed_texture_pvrtc)) arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_compressed_texture_pvrtc")); if (IsExtensionSupported(cx, WebGLExtensionID::WEBGL_depth_texture)) arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_depth_texture")); }
void WebGL2Context::GetUniformIndices(WebGLProgram* program, const dom::Sequence<nsString>& uniformNames, dom::Nullable< nsTArray<GLuint> >& retval) { retval.SetNull(); if (IsContextLost()) return; if (!ValidateObject("getUniformIndices: program", program)) return; if (!uniformNames.Length()) return; GLuint progname = program->mGLName; size_t count = uniformNames.Length(); nsTArray<GLuint>& arr = retval.SetValue(); MakeContextCurrent(); for (size_t n = 0; n < count; n++) { NS_LossyConvertUTF16toASCII name(uniformNames[n]); // const GLchar* glname = name.get(); const GLchar* glname = nullptr; name.BeginReading(glname); GLuint index = 0; gl->fGetUniformIndices(progname, 1, &glname, &index); arr.AppendElement(index); } }
void WebGLProgram::GetActiveUniformBlockParam(GLuint uniformBlockIndex, GLenum pname, dom::Nullable<dom::OwningUnsignedLongOrUint32ArrayOrBoolean>& retval) const { retval.SetNull(); if (!IsLinked()) { mContext->ErrorInvalidOperation("getActiveUniformBlockParameter: `program` must be linked."); return; } const webgl::LinkedProgramInfo* linkInfo = LinkInfo(); GLuint uniformBlockCount = (GLuint)linkInfo->uniformBlocks.size(); if (uniformBlockIndex >= uniformBlockCount) { mContext->ErrorInvalidValue("getActiveUniformBlockParameter: index %u invalid.", uniformBlockIndex); return; } gl::GLContext* gl = mContext->GL(); GLint param = 0; switch (pname) { case LOCAL_GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER: case LOCAL_GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER: gl->fGetActiveUniformBlockiv(mGLName, uniformBlockIndex, pname, ¶m); retval.SetValue().SetAsBoolean() = (param != 0); return; case LOCAL_GL_UNIFORM_BLOCK_BINDING: case LOCAL_GL_UNIFORM_BLOCK_DATA_SIZE: case LOCAL_GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS: gl->fGetActiveUniformBlockiv(mGLName, uniformBlockIndex, pname, ¶m); retval.SetValue().SetAsUnsignedLong() = param; return; } }
void WebGLContext::BufferSubData(GLenum target, WebGLsizeiptr byteOffset, const dom::Nullable<dom::ArrayBuffer>& maybeData) { if (maybeData.IsNull()) { // see http://www.khronos.org/bugzilla/show_bug.cgi?id=386 return; } BufferSubDataT(target, byteOffset, maybeData.Value()); }
void WebGL2Context::GetBufferSubData(GLenum target, GLintptr offset, const dom::Nullable<dom::ArrayBuffer>& maybeData) { // If returnedData is null then an INVALID_VALUE error is // generated. if (maybeData.IsNull()) return ErrorInvalidValue("getBufferSubData: returnedData is null"); const dom::ArrayBuffer& data = maybeData.Value(); GetBufferSubDataT(target, offset, data); }
void WebGLContext::BufferData(GLenum target, const dom::Nullable<dom::ArrayBuffer>& maybeData, GLenum usage) { if (maybeData.IsNull()) { // see http://www.khronos.org/bugzilla/show_bug.cgi?id=386 return ErrorInvalidValue("bufferData: null object passed"); } BufferDataT(target, maybeData.Value(), usage); }
void WebGL2Context::GetActiveUniformBlockParameter(JSContext* cx, WebGLProgram* program, GLuint uniformBlockIndex, GLenum pname, dom::Nullable<dom::OwningUnsignedLongOrUint32ArrayOrBoolean>& retval, ErrorResult& rv) { retval.SetNull(); if (IsContextLost()) return; if (!ValidateObject("getActiveUniformBlockParameter: program", program)) return; MakeContextCurrent(); switch(pname) { case LOCAL_GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER: case LOCAL_GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER: case LOCAL_GL_UNIFORM_BLOCK_BINDING: case LOCAL_GL_UNIFORM_BLOCK_DATA_SIZE: case LOCAL_GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS: program->GetActiveUniformBlockParam(uniformBlockIndex, pname, retval); return; case LOCAL_GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES: program->GetActiveUniformBlockActiveUniforms(cx, uniformBlockIndex, retval, rv); return; } ErrorInvalidEnumInfo("getActiveUniformBlockParameter: parameter", pname); }
void DominatorTree::GetImmediatelyDominated(uint64_t aNodeId, dom::Nullable<nsTArray<uint64_t>>& aOutResult, ErrorResult& aRv) { MOZ_ASSERT(aOutResult.IsNull()); JS::ubi::Node::Id id(aNodeId); Maybe<JS::ubi::Node> node = mHeapSnapshot->getNodeById(id); if (node.isNothing()) return; // Get all immediately dominated nodes and their retained sizes. MallocSizeOf mallocSizeOf = getCurrentThreadDebuggerMallocSizeOf(); Maybe<JS::ubi::DominatorTree::DominatedSetRange> range = mDominatorTree.getDominatedSet(*node); MOZ_ASSERT(range.isSome(), "The node should be known, since we got it from the heap snapshot."); size_t length = range->length(); nsTArray<NodeAndRetainedSize> dominatedNodes(length); for (const JS::ubi::Node& dominatedNode : *range) { JS::ubi::Node::Size retainedSize = 0; if (NS_WARN_IF(!mDominatorTree.getRetainedSize(dominatedNode, mallocSizeOf, retainedSize))) { aRv.Throw(NS_ERROR_OUT_OF_MEMORY); return; } MOZ_ASSERT(retainedSize != 0, "retainedSize should not be zero since we know the node is in the dominator tree."); dominatedNodes.AppendElement(NodeAndRetainedSize(dominatedNode, retainedSize)); } // Sort them by retained size. NodeAndRetainedSize::Comparator comparator; dominatedNodes.Sort(comparator); // Fill the result with the nodes' ids. JS::ubi::Node root = mDominatorTree.root(); aOutResult.SetValue(nsTArray<uint64_t>(length)); for (const NodeAndRetainedSize& entry : dominatedNodes) { // The root dominates itself, but we don't want to expose that to JS. if (entry.mNode == root) continue; aOutResult.Value().AppendElement(entry.mNode.identifier()); } }
/* This doesn't belong here. It's part of state querying */ void WebGL2Context::GetIndexedParameter(GLenum target, GLuint index, dom::Nullable<dom::OwningWebGLBufferOrLongLong>& retval) { retval.SetNull(); if (IsContextLost()) return; GLint64 data = 0; MakeContextCurrent(); switch (target) { case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: if (index >= mGLMaxTransformFeedbackSeparateAttribs) return ErrorInvalidValue("getIndexedParameter: index should be less than " "MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS"); retval.SetValue().SetAsWebGLBuffer() = mBoundTransformFeedbackBuffers[index].get(); return; case LOCAL_GL_UNIFORM_BUFFER_BINDING: if (index >= mGLMaxUniformBufferBindings) return ErrorInvalidValue("getIndexedParameter: index should be than " "MAX_UNIFORM_BUFFER_BINDINGS"); retval.SetValue().SetAsWebGLBuffer() = mBoundUniformBuffers[index].get(); return; case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_START: case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_SIZE: case LOCAL_GL_UNIFORM_BUFFER_START: case LOCAL_GL_UNIFORM_BUFFER_SIZE: gl->fGetInteger64i_v(target, index, &data); retval.SetValue().SetAsLongLong() = data; return; } ErrorInvalidEnumInfo("getIndexedParameter: target", target); }
void WebGLContext::BufferData(GLenum target, const dom::Nullable<dom::ArrayBuffer>& maybeSrc, GLenum usage) { const FuncScope funcScope(*this, "bufferData"); if (IsContextLost()) return; if (!ValidateNonNull("src", maybeSrc)) return; const auto& src = maybeSrc.Value(); src.ComputeLengthAndData(); BufferDataImpl(target, src.LengthAllowShared(), src.DataAllowShared(), usage); }
void WebGLContext::GetSupportedExtensions(dom::Nullable< nsTArray<nsString> >& retval, dom::CallerType callerType) { retval.SetNull(); if (IsContextLost()) return; nsTArray<nsString>& arr = retval.SetValue(); for (size_t i = 0; i < size_t(WebGLExtensionID::Max); i++) { const auto extension = WebGLExtensionID(i); if (extension == WebGLExtensionID::MOZ_debug) continue; // Hide MOZ_debug from this list. if (IsExtensionSupported(callerType, extension)) { const char* extStr = GetExtensionString(extension); arr.AppendElement(NS_ConvertUTF8toUTF16(extStr)); } } }
void WebGL2Context::GetUniformIndices( const WebGLProgram& program, const dom::Sequence<nsString>& uniformNames, dom::Nullable<nsTArray<GLuint> >& retval) { const FuncScope funcScope(*this, "getUniformIndices"); retval.SetNull(); if (IsContextLost()) return; if (!ValidateObject("program", program)) return; if (!uniformNames.Length()) return; program.GetUniformIndices(uniformNames, retval); }
void WebGLProgram::GetUniformIndices(const dom::Sequence<nsString>& uniformNames, dom::Nullable< nsTArray<GLuint> >& retval) const { const char funcName[] = "getUniformIndices"; if (!IsLinked()) { mContext->ErrorInvalidOperation("%s: `program` must be linked.", funcName); return; } size_t count = uniformNames.Length(); nsTArray<GLuint>& arr = retval.SetValue(); gl::GLContext* gl = mContext->GL(); gl->MakeCurrent(); for (size_t i = 0; i < count; i++) { const NS_LossyConvertUTF16toASCII userName(uniformNames[i]); nsDependentCString baseUserName; bool isArray; size_t arrayIndex; if (!ParseName(userName, &baseUserName, &isArray, &arrayIndex)) { arr.AppendElement(LOCAL_GL_INVALID_INDEX); continue; } webgl::UniformInfo* info; if (!LinkInfo()->FindUniform(baseUserName, &info)) { arr.AppendElement(LOCAL_GL_INVALID_INDEX); continue; } nsAutoCString mappedName(info->mActiveInfo->mBaseMappedName); if (isArray) { mappedName.AppendLiteral("["); mappedName.AppendInt(uint32_t(arrayIndex)); mappedName.AppendLiteral("]"); } const GLchar* mappedNameBytes = mappedName.BeginReading(); GLuint index = 0; gl->fGetUniformIndices(mGLName, 1, &mappedNameBytes, &index); arr.AppendElement(index); } }
void WebGL2Context::GetUniformIndices(WebGLProgram* program, const dom::Sequence<nsString>& uniformNames, dom::Nullable< nsTArray<GLuint> >& retval) { retval.SetNull(); if (IsContextLost()) return; if (!ValidateObject("getUniformIndices: program", program)) return; if (!uniformNames.Length()) return; program->GetUniformIndices(uniformNames, retval); }
void WebGLProgram::GetActiveUniformBlockActiveUniforms(JSContext* cx, GLuint uniformBlockIndex, dom::Nullable<dom::OwningUnsignedLongOrUint32ArrayOrBoolean>& retval, ErrorResult& rv) const { if (!IsLinked()) { mContext->ErrorInvalidOperation("getActiveUniformBlockParameter: `program` must be linked."); return; } const webgl::LinkedProgramInfo* linkInfo = LinkInfo(); GLuint uniformBlockCount = (GLuint)linkInfo->uniformBlocks.size(); if (uniformBlockIndex >= uniformBlockCount) { mContext->ErrorInvalidValue("getActiveUniformBlockParameter: index %u invalid.", uniformBlockIndex); return; } gl::GLContext* gl = mContext->GL(); GLint activeUniformCount = 0; gl->fGetActiveUniformBlockiv(mGLName, uniformBlockIndex, LOCAL_GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &activeUniformCount); JS::RootedObject obj(cx, dom::Uint32Array::Create(cx, mContext, activeUniformCount, nullptr)); if (!obj) { rv = NS_ERROR_OUT_OF_MEMORY; return; } dom::Uint32Array result; DebugOnly<bool> inited = result.Init(obj); MOZ_ASSERT(inited); result.ComputeLengthAndData(); gl->fGetActiveUniformBlockiv(mGLName, uniformBlockIndex, LOCAL_GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, (GLint*)result.Data()); inited = retval.SetValue().SetAsUint32Array().Init(obj); MOZ_ASSERT(inited); }
void WebGL2Context::GetBufferSubData(GLenum target, GLintptr offset, const dom::Nullable<dom::ArrayBuffer>& maybeData) { if (IsContextLost()) return; // For the WebGLBuffer bound to the passed target, read // returnedData.byteLength bytes from the buffer starting at byte // offset offset and write them to returnedData. // If zero is bound to target, an INVALID_OPERATION error is // generated. if (!ValidateBufferTarget(target, "getBufferSubData")) return; // If offset is less than zero, an INVALID_VALUE error is // generated. if (offset < 0) return ErrorInvalidValue("getBufferSubData: negative offset"); // If returnedData is null then an INVALID_VALUE error is // generated. if (maybeData.IsNull()) return ErrorInvalidValue("getBufferSubData: returnedData is null"); WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target); WebGLBuffer* boundBuffer = bufferSlot.get(); if (!boundBuffer) return ErrorInvalidOperation("getBufferSubData: no buffer bound"); // If offset + returnedData.byteLength would extend beyond the end // of the buffer an INVALID_VALUE error is generated. const dom::ArrayBuffer& data = maybeData.Value(); data.ComputeLengthAndData(); CheckedInt<WebGLsizeiptr> neededByteLength = CheckedInt<WebGLsizeiptr>(offset) + data.Length(); if (!neededByteLength.isValid()) { ErrorInvalidValue("getBufferSubData: Integer overflow computing the needed" " byte length."); return; } if (neededByteLength.value() > boundBuffer->ByteLength()) { ErrorInvalidValue("getBufferSubData: Not enough data. Operation requires" " %d bytes, but buffer only has %d bytes.", neededByteLength.value(), boundBuffer->ByteLength()); return; } // If target is TRANSFORM_FEEDBACK_BUFFER, and any transform // feedback object is currently active, an INVALID_OPERATION error // is generated. WebGLTransformFeedback* currentTF = mBoundTransformFeedback; if (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER && currentTF) { if (currentTF->mIsActive) return ErrorInvalidOperation("getBufferSubData: Currently bound transform" " feedback is active"); // https://github.com/NVIDIA/WebGL/commit/63aff5e58c1d79825a596f0f4aa46174b9a5f72c // Performing reads and writes on a buffer that is currently // bound for transform feedback causes undefined results in // GLES3.0 and OpenGL 4.5. In practice results of reads and // writes might be consistent as long as transform feedback // objects are not active, but neither GLES3.0 nor OpenGL 4.5 // spec guarantees this - just being bound for transform // feedback is sufficient to cause undefined results. BindTransformFeedback(LOCAL_GL_TRANSFORM_FEEDBACK, nullptr); } /* If the buffer is written and read sequentially by other * operations and getBufferSubData, it is the responsibility of * the WebGL API to ensure that data are access * consistently. This applies even if the buffer is currently * bound to a transform feedback binding point. */ void* ptr = gl->fMapBufferRange(target, offset, data.Length(), LOCAL_GL_MAP_READ_BIT); memcpy(data.Data(), ptr, data.Length()); gl->fUnmapBuffer(target); if (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER && currentTF) { BindTransformFeedback(LOCAL_GL_TRANSFORM_FEEDBACK, currentTF); } }