예제 #1
0
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());
}
예제 #2
0
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"));
}
예제 #3
0
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);
    }
}
예제 #4
0
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, &param);
        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, &param);
        retval.SetValue().SetAsUnsignedLong() = param;
        return;
    }
}
예제 #5
0
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());
}
예제 #6
0
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);
}
예제 #7
0
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);
}
예제 #8
0
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);
}
예제 #9
0
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());
    }
}
예제 #10
0
/* 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);
}
예제 #11
0
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);
}
예제 #12
0
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));
        }
    }
}
예제 #13
0
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);
}
예제 #14
0
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);
}
예제 #16
0
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);
}
예제 #17
0
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);
    }
}