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 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 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()); } }
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); } }