Example #1
0
static bool
ValidateUnpackPixels(WebGLContext* webgl, const char* funcName, uint32_t fullRows,
                     uint32_t tailPixels, webgl::TexUnpackBlob* blob)
{
    if (!blob->mWidth || !blob->mHeight || !blob->mDepth)
        return true;

    const auto usedPixelsPerRow = CheckedUint32(blob->mSkipPixels) + blob->mWidth;
    if (!usedPixelsPerRow.isValid() || usedPixelsPerRow.value() > blob->mRowLength) {
        webgl->ErrorInvalidOperation("%s: UNPACK_SKIP_PIXELS + width >"
                                     " UNPACK_ROW_LENGTH.",
                                     funcName);
        return false;
    }

    if (blob->mHeight > blob->mImageHeight) {
        webgl->ErrorInvalidOperation("%s: height > UNPACK_IMAGE_HEIGHT.", funcName);
        return false;
    }

    //////

    // The spec doesn't bound SKIP_ROWS + height <= IMAGE_HEIGHT, unfortunately.
    auto skipFullRows = CheckedUint32(blob->mSkipImages) * blob->mImageHeight;
    skipFullRows += blob->mSkipRows;

    MOZ_ASSERT(blob->mDepth >= 1);
    MOZ_ASSERT(blob->mHeight >= 1);
    auto usedFullRows = CheckedUint32(blob->mDepth - 1) * blob->mImageHeight;
    usedFullRows += blob->mHeight - 1; // Full rows in the final image, excluding the tail.

    const auto fullRowsNeeded = skipFullRows + usedFullRows;
    if (!fullRowsNeeded.isValid()) {
        webgl->ErrorOutOfMemory("%s: Invalid calculation for required row count.",
                                funcName);
        return false;
    }

    if (fullRows > fullRowsNeeded.value())
        return true;

    if (fullRows == fullRowsNeeded.value() && tailPixels >= usedPixelsPerRow.value()) {
        blob->mNeedsExactUpload = true;
        return true;
    }

    webgl->ErrorInvalidOperation("%s: Desired upload requires more data than is"
                                 " available: (%u rows plus %u pixels needed, %u rows"
                                 " plus %u pixels available)",
                                 funcName, fullRowsNeeded.value(),
                                 usedPixelsPerRow.value(), fullRows, tailPixels);
    return false;
}
Example #2
0
nsresult nsRawReader::Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime)
{
  NS_ASSERTION(mDecoder->OnDecodeThread(),
               "Should be on decode thread.");

  MediaResource *resource = mDecoder->GetResource();
  NS_ASSERTION(resource, "Decoder has no media resource");

  uint32_t frame = mCurrentFrame;
  if (aTime >= UINT_MAX)
    return NS_ERROR_FAILURE;
  mCurrentFrame = aTime * mFrameRate / USECS_PER_S;

  CheckedUint32 offset = CheckedUint32(mCurrentFrame) * mFrameSize;
  offset += sizeof(nsRawVideoHeader);
  NS_ENSURE_TRUE(offset.isValid(), NS_ERROR_FAILURE);

  nsresult rv = resource->Seek(nsISeekableStream::NS_SEEK_SET, offset.value());
  NS_ENSURE_SUCCESS(rv, rv);

  mVideoQueue.Erase();

  while(mVideoQueue.GetSize() == 0) {
    bool keyframeSkip = false;
    if (!DecodeVideoFrame(keyframeSkip, 0)) {
      mCurrentFrame = frame;
      return NS_ERROR_FAILURE;
    }

    {
      mozilla::ReentrantMonitorAutoEnter autoMonitor(mDecoder->GetReentrantMonitor());
      if (mDecoder->GetDecodeState() ==
          nsBuiltinDecoderStateMachine::DECODER_STATE_SHUTDOWN) {
        mCurrentFrame = frame;
        return NS_ERROR_FAILURE;
      }
    }

    nsAutoPtr<VideoData> video(mVideoQueue.PeekFront());
    if (video && video->mEndTime < aTime) {
      mVideoQueue.PopFront();
      video = nullptr;
    } else {
      video.forget();
    }
  }

  return NS_OK;
}
Example #3
0
void
AudioStream::GetTimeStretched(AudioBufferWriter& aWriter)
{
  mMonitor.AssertCurrentThreadOwns();

  // We need to call the non-locking version, because we already have the lock.
  if (EnsureTimeStretcherInitializedUnlocked() != NS_OK) {
    return;
  }

  uint32_t toPopFrames =
    ceil(aWriter.Available() * mAudioClock.GetPlaybackRate());

  while (mTimeStretcher->numSamples() < aWriter.Available()) {
    UniquePtr<Chunk> c = mDataSource.PopFrames(toPopFrames);
    if (c->Frames() == 0) {
      break;
    }
    MOZ_ASSERT(c->Frames() <= toPopFrames);
    if (IsValidAudioFormat(c.get())) {
      mTimeStretcher->putSamples(c->Data(), c->Frames());
    } else {
      // Write silence if invalid format.
      AutoTArray<AudioDataValue, 1000> buf;
      auto size = CheckedUint32(mOutChannels) * c->Frames();
      if (!size.isValid()) {
        // The overflow should not happen in normal case.
        LOGW("Invalid member data: %d channels, %d frames", mOutChannels, c->Frames());
        return;
      }
      buf.SetLength(size.value());
      size = size * sizeof(AudioDataValue);
      if (!size.isValid()) {
        LOGW("The required memory size is too large.");
        return;
      }
      memset(buf.Elements(), 0, size.value());
      mTimeStretcher->putSamples(buf.Elements(), c->Frames());
    }
  }

  auto timeStretcher = mTimeStretcher;
  aWriter.Write([timeStretcher] (AudioDataValue* aPtr, uint32_t aFrames) {
    return timeStretcher->receiveSamples(aPtr, aFrames);
  }, aWriter.Available());
}
Example #4
0
static bool
ValidateUnpackBytes(WebGLContext* webgl, const char* funcName,
                    const webgl::PackingInfo& pi, size_t availByteCount,
                    webgl::TexUnpackBlob* blob)
{
    if (!blob->mWidth || !blob->mHeight || !blob->mDepth)
        return true;

    const auto bytesPerPixel = webgl::BytesPerPixel(pi);
    const auto bytesPerRow = CheckedUint32(blob->mRowLength) * bytesPerPixel;
    const auto rowStride = RoundUpToMultipleOf(bytesPerRow, blob->mAlignment);

    const auto fullRows = availByteCount / rowStride;
    if (!fullRows.isValid()) {
        webgl->ErrorOutOfMemory("%s: Unacceptable upload size calculated.", funcName);
        return false;
    }

    const auto bodyBytes = fullRows.value() * rowStride.value();
    const auto tailPixels = (availByteCount - bodyBytes) / bytesPerPixel;

    return ValidateUnpackPixels(webgl, funcName, fullRows.value(), tailPixels, blob);
}
Example #5
0
bool
TexUnpackBytes::TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName,
                              WebGLTexture* tex, TexImageTarget target, GLint level,
                              const webgl::DriverUnpackInfo* dui, GLint xOffset,
                              GLint yOffset, GLint zOffset, const webgl::PackingInfo& pi,
                              GLenum* const out_error) const
{
    WebGLContext* webgl = tex->mContext;

    const auto format = FormatForPackingInfo(pi);
    const auto bytesPerPixel = webgl::BytesPerPixel(pi);

    const uint8_t* uploadPtr = mPtr;
    UniqueBuffer tempBuffer;

    do {
        if (!mIsClientData || !mPtr)
            break;

        if (!webgl->mPixelStore_FlipY &&
            !webgl->mPixelStore_PremultiplyAlpha)
        {
            break;
        }

        if (webgl->mPixelStore_UnpackImageHeight ||
            webgl->mPixelStore_UnpackSkipImages ||
            webgl->mPixelStore_UnpackRowLength ||
            webgl->mPixelStore_UnpackSkipRows ||
            webgl->mPixelStore_UnpackSkipPixels)
        {
            webgl->ErrorInvalidOperation("%s: Non-DOM-Element uploads with alpha-premult"
                                         " or y-flip do not support subrect selection.",
                                         funcName);
            return false;
        }

        webgl->GenerateWarning("%s: Alpha-premult and y-flip are deprecated for"
                               " non-DOM-Element uploads.",
                               funcName);

        const uint32_t rowLength = mWidth;
        const uint32_t rowCount = mHeight * mDepth;
        const auto stride = RoundUpToMultipleOf(rowLength * bytesPerPixel, mAlignment);
        if (!ConvertIfNeeded(webgl, funcName, rowLength, rowCount, format, mPtr, stride,
                             format, stride, &uploadPtr, &tempBuffer))
        {
            return false;
        }
    } while (false);

    //////

    const auto& gl = webgl->gl;

    bool useParanoidHandling = false;
    if (mNeedsExactUpload && webgl->mBoundPixelUnpackBuffer) {
        webgl->GenerateWarning("%s: Uploads from a buffer with a final row with a byte"
                               " count smaller than the row stride can incur extra"
                               " overhead.",
                               funcName);

        if (gl->WorkAroundDriverBugs()) {
            useParanoidHandling |= (gl->Vendor() == gl::GLVendor::NVIDIA);
        }
    }

    if (!useParanoidHandling) {
        if (webgl->mBoundPixelUnpackBuffer) {
            gl->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER,
                            webgl->mBoundPixelUnpackBuffer->mGLName);
        }

        *out_error = DoTexOrSubImage(isSubImage, gl, target, level, dui, xOffset, yOffset,
                                     zOffset, mWidth, mHeight, mDepth, uploadPtr);

        if (webgl->mBoundPixelUnpackBuffer) {
            gl->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, 0);
        }
        return true;
    }

    //////

    MOZ_ASSERT(webgl->mBoundPixelUnpackBuffer);

    if (!isSubImage) {
        // Alloc first to catch OOMs.
        AssertUintParamCorrect(gl, LOCAL_GL_PIXEL_UNPACK_BUFFER, 0);
        *out_error = DoTexOrSubImage(false, gl, target, level, dui, xOffset, yOffset,
                                     zOffset, mWidth, mHeight, mDepth, nullptr);
        if (*out_error)
            return true;
    }

    const ScopedLazyBind bindPBO(gl, LOCAL_GL_PIXEL_UNPACK_BUFFER,
                                 webgl->mBoundPixelUnpackBuffer);

    //////

    // Make our sometimes-implicit values explicit. Also this keeps them constant when we
    // ask for height=mHeight-1 and such.
    gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, mRowLength);
    gl->fPixelStorei(LOCAL_GL_UNPACK_IMAGE_HEIGHT, mImageHeight);

    if (mDepth > 1) {
        *out_error = DoTexOrSubImage(true, gl, target, level, dui, xOffset, yOffset,
                                     zOffset, mWidth, mHeight, mDepth-1, uploadPtr);
    }

    // Skip the images we uploaded.
    gl->fPixelStorei(LOCAL_GL_UNPACK_SKIP_IMAGES, mSkipImages + mDepth - 1);

    if (mHeight > 1) {
        *out_error = DoTexOrSubImage(true, gl, target, level, dui, xOffset, yOffset,
                                     zOffset+mDepth-1, mWidth, mHeight-1, 1, uploadPtr);
    }

    const auto totalSkipRows = CheckedUint32(mSkipImages) * mImageHeight + mSkipRows;
    const auto totalFullRows = CheckedUint32(mDepth - 1) * mImageHeight + mHeight - 1;
    const auto tailOffsetRows = totalSkipRows + totalFullRows;

    const auto bytesPerRow = CheckedUint32(mRowLength) * bytesPerPixel;
    const auto rowStride = RoundUpToMultipleOf(bytesPerRow, mAlignment);
    if (!rowStride.isValid()) {
        MOZ_CRASH("Should be checked earlier.");
    }
    const auto tailOffsetBytes = tailOffsetRows * rowStride;

    uploadPtr += tailOffsetBytes.value();

    //////

    gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 1);   // No stride padding.
    gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, 0);  // No padding in general.
    gl->fPixelStorei(LOCAL_GL_UNPACK_SKIP_IMAGES, 0); // Don't skip images,
    gl->fPixelStorei(LOCAL_GL_UNPACK_SKIP_ROWS, 0);   // or rows.
                                                      // Keep skipping pixels though!

    *out_error = DoTexOrSubImage(true, gl, target, level, dui, xOffset,
                                 yOffset+mHeight-1, zOffset+mDepth-1, mWidth, 1, 1,
                                 uploadPtr);

    // Reset all our modified state.
    gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, webgl->mPixelStore_UnpackAlignment);
    gl->fPixelStorei(LOCAL_GL_UNPACK_IMAGE_HEIGHT, webgl->mPixelStore_UnpackImageHeight);
    gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, webgl->mPixelStore_UnpackRowLength);
    gl->fPixelStorei(LOCAL_GL_UNPACK_SKIP_IMAGES, webgl->mPixelStore_UnpackSkipImages);
    gl->fPixelStorei(LOCAL_GL_UNPACK_SKIP_ROWS, webgl->mPixelStore_UnpackSkipRows);

    return true;
}
Example #6
0
bool
TexUnpackBlob::ConvertIfNeeded(WebGLContext* webgl, const char* funcName,
                               const uint32_t rowLength, const uint32_t rowCount,
                               WebGLTexelFormat srcFormat,
                               const uint8_t* const srcBegin, const ptrdiff_t srcStride,
                               WebGLTexelFormat dstFormat, const ptrdiff_t dstStride,
                               const uint8_t** const out_begin,
                               UniqueBuffer* const out_anchoredBuffer) const
{
    MOZ_ASSERT(srcFormat != WebGLTexelFormat::FormatNotSupportingAnyConversion);
    MOZ_ASSERT(dstFormat != WebGLTexelFormat::FormatNotSupportingAnyConversion);

    *out_begin = srcBegin;

    if (!rowLength || !rowCount)
        return true;

    const auto srcIsPremult = (mSrcAlphaType == gfxAlphaType::Premult);
    const auto& dstIsPremult = webgl->mPixelStore_PremultiplyAlpha;
    const auto fnHasPremultMismatch = [&]() {
        if (mSrcAlphaType == gfxAlphaType::Opaque)
            return false;

        if (!HasColorAndAlpha(srcFormat))
            return false;

        return srcIsPremult != dstIsPremult;
    };

    const auto srcOrigin = (webgl->mPixelStore_FlipY ? gl::OriginPos::TopLeft
                                                     : gl::OriginPos::BottomLeft);
    const auto dstOrigin = gl::OriginPos::BottomLeft;

    if (srcFormat != dstFormat) {
        webgl->GeneratePerfWarning("%s: Conversion requires pixel reformatting. (%u->%u)",
                                   funcName, uint32_t(srcFormat),
                                   uint32_t(dstFormat));
    } else if (fnHasPremultMismatch()) {
        webgl->GeneratePerfWarning("%s: Conversion requires change in"
                                   " alpha-premultiplication.",
                                   funcName);
    } else if (srcOrigin != dstOrigin) {
        webgl->GeneratePerfWarning("%s: Conversion requires y-flip.", funcName);
    } else if (srcStride != dstStride) {
        webgl->GeneratePerfWarning("%s: Conversion requires change in stride. (%u->%u)",
                                   funcName, uint32_t(srcStride), uint32_t(dstStride));
    } else {
        return true;
    }

    ////

    const auto dstTotalBytes = CheckedUint32(rowCount) * dstStride;
    if (!dstTotalBytes.isValid()) {
        webgl->ErrorOutOfMemory("%s: Calculation failed.", funcName);
        return false;
    }

    UniqueBuffer dstBuffer = calloc(1, dstTotalBytes.value());
    if (!dstBuffer.get()) {
        webgl->ErrorOutOfMemory("%s: Failed to allocate dest buffer.", funcName);
        return false;
    }
    const auto dstBegin = static_cast<uint8_t*>(dstBuffer.get());

    ////

    // And go!:
    bool wasTrivial;
    if (!ConvertImage(rowLength, rowCount,
                      srcBegin, srcStride, srcOrigin, srcFormat, srcIsPremult,
                      dstBegin, dstStride, dstOrigin, dstFormat, dstIsPremult,
                      &wasTrivial))
    {
        webgl->ErrorImplementationBug("%s: ConvertImage failed.", funcName);
        return false;
    }

    *out_begin = dstBegin;
    *out_anchoredBuffer = Move(dstBuffer);
    return true;
}
bool
TexUnpackBlob::ConvertIfNeeded(WebGLContext* webgl, const char* funcName,
                               const uint8_t* srcBytes, uint32_t srcStride,
                               uint8_t srcBPP, WebGLTexelFormat srcFormat,
                               const webgl::DriverUnpackInfo* dstDUI,
                               const uint8_t** const out_bytes,
                               UniqueBuffer* const out_anchoredBuffer) const
{
    *out_bytes = srcBytes;

    if (!HasData() || !mWidth || !mHeight || !mDepth)
        return true;

    //////

    const auto totalSkipRows = mSkipRows + CheckedUint32(mSkipImages) * mImageHeight;
    const auto offset = mSkipPixels * CheckedUint32(srcBPP) + totalSkipRows * srcStride;
    if (!offset.isValid()) {
        webgl->ErrorOutOfMemory("%s: Invalid offset calculation during conversion.",
                                funcName);
        return false;
    }
    const uint32_t skipBytes = offset.value();

    auto const srcBegin = srcBytes + skipBytes;

    //////

    const auto srcOrigin = (webgl->mPixelStore_FlipY ? gl::OriginPos::TopLeft
                                                     : gl::OriginPos::BottomLeft);
    const auto dstOrigin = gl::OriginPos::BottomLeft;
    const bool isDstPremult = webgl->mPixelStore_PremultiplyAlpha;

    const auto pi = dstDUI->ToPacking();

    const auto dstBPP = webgl::BytesPerPixel(pi);
    const auto dstWidthBytes = CheckedUint32(dstBPP) * mWidth;
    const auto dstRowLengthBytes = CheckedUint32(dstBPP) * mRowLength;

    const auto dstAlignment = mAlignment;
    const auto dstStride = RoundUpToMultipleOf(dstRowLengthBytes, dstAlignment);

    //////

    const auto dstTotalRows = CheckedUint32(mDepth - 1) * mImageHeight + mHeight;
    const auto dstUsedSizeExceptLastRow = (dstTotalRows - 1) * dstStride;

    const auto dstSize = skipBytes + dstUsedSizeExceptLastRow + dstWidthBytes;
    if (!dstSize.isValid()) {
        webgl->ErrorOutOfMemory("%s: Invalid dstSize calculation during conversion.",
                                funcName);
        return false;
    }

    //////

    const auto dstFormat = FormatForPackingInfo(pi);

    bool premultMatches = (mIsSrcPremult == isDstPremult);
    if (!UnpackFormatHasColorAndAlpha(dstDUI->unpackFormat)) {
        premultMatches = true;
    }

    const bool needsPixelConversion = (srcFormat != dstFormat || !premultMatches);
    const bool originsMatch = (srcOrigin == dstOrigin);

    MOZ_ASSERT_IF(!needsPixelConversion, srcBPP == dstBPP);

    if (!needsPixelConversion &&
        originsMatch &&
        srcStride == dstStride.value())
    {
        // No conversion needed!
        return true;
    }

    //////
    // We need some sort of conversion, so create the dest buffer.

    *out_anchoredBuffer = calloc(1, dstSize.value());
    const auto dstBytes = (uint8_t*)out_anchoredBuffer->get();

    if (!dstBytes) {
        webgl->ErrorOutOfMemory("%s: Unable to allocate buffer during conversion.",
                                funcName);
        return false;
    }
    *out_bytes = dstBytes;
    const auto dstBegin = dstBytes + skipBytes;

    //////
    // Row conversion

    if (!needsPixelConversion) {
        webgl->GenerateWarning("%s: Incurred CPU row conversion, which is slow.",
                               funcName);

        const uint8_t* srcRow = srcBegin;
        uint8_t* dstRow = dstBegin;
        const auto widthBytes = dstWidthBytes.value();
        ptrdiff_t dstCopyStride = dstStride.value();

        if (!originsMatch) {
            dstRow += dstUsedSizeExceptLastRow.value();
            dstCopyStride = -dstCopyStride;
        }

        for (uint32_t i = 0; i < dstTotalRows.value(); i++) {
            memcpy(dstRow, srcRow, widthBytes);
            srcRow += srcStride;
            dstRow += dstCopyStride;
        }
        return true;
    }

    ////////////
    // Pixel conversion.

    MOZ_ASSERT(srcFormat != WebGLTexelFormat::FormatNotSupportingAnyConversion);
    MOZ_ASSERT(dstFormat != WebGLTexelFormat::FormatNotSupportingAnyConversion);

    webgl->GenerateWarning("%s: Incurred CPU pixel conversion, which is very slow.",
                           funcName);

    //////

    // And go!:
    bool wasTrivial;
    if (!ConvertImage(mWidth, dstTotalRows.value(),
                      srcBegin, srcStride, srcOrigin, srcFormat, mIsSrcPremult,
                      dstBegin, dstStride.value(), dstOrigin, dstFormat, isDstPremult,
                      &wasTrivial))
    {
        webgl->ErrorImplementationBug("%s: ConvertImage failed.", funcName);
        return false;
    }

    if (!wasTrivial) {
        webgl->GenerateWarning("%s: Chosen format/type incurred an expensive reformat:"
                               " 0x%04x/0x%04x",
                               funcName, dstDUI->unpackFormat, dstDUI->unpackType);
    }

    return true;
}
bool
WebGLContext::DoFakeVertexAttrib0(GLuint vertexCount)
{
    WebGLVertexAttrib0Status whatDoesAttrib0Need = WhatDoesVertexAttrib0Need();

    if (MOZ_LIKELY(whatDoesAttrib0Need == WebGLVertexAttrib0Status::Default))
        return true;

    if (!mAlreadyWarnedAboutFakeVertexAttrib0) {
        GenerateWarning("Drawing without vertex attrib 0 array enabled forces the browser "
                        "to do expensive emulation work when running on desktop OpenGL "
                        "platforms, for example on Mac. It is preferable to always draw "
                        "with vertex attrib 0 array enabled, by using bindAttribLocation "
                        "to bind some always-used attribute to location 0.");
        mAlreadyWarnedAboutFakeVertexAttrib0 = true;
    }

    CheckedUint32 checked_dataSize = CheckedUint32(vertexCount) * 4 * sizeof(GLfloat);

    if (!checked_dataSize.isValid()) {
        ErrorOutOfMemory("Integer overflow trying to construct a fake vertex attrib 0 array for a draw-operation "
                         "with %d vertices. Try reducing the number of vertices.", vertexCount);
        return false;
    }

    GLuint dataSize = checked_dataSize.value();

    if (!mFakeVertexAttrib0BufferObject) {
        gl->fGenBuffers(1, &mFakeVertexAttrib0BufferObject);
    }

    // if the VBO status is already exactly what we need, or if the only difference is that it's initialized and
    // we don't need it to be, then consider it OK
    bool vertexAttrib0BufferStatusOK =
        mFakeVertexAttrib0BufferStatus == whatDoesAttrib0Need ||
        (mFakeVertexAttrib0BufferStatus == WebGLVertexAttrib0Status::EmulatedInitializedArray &&
         whatDoesAttrib0Need == WebGLVertexAttrib0Status::EmulatedUninitializedArray);

    if (!vertexAttrib0BufferStatusOK ||
        mFakeVertexAttrib0BufferObjectSize < dataSize ||
        mFakeVertexAttrib0BufferObjectVector[0] != mVertexAttrib0Vector[0] ||
        mFakeVertexAttrib0BufferObjectVector[1] != mVertexAttrib0Vector[1] ||
        mFakeVertexAttrib0BufferObjectVector[2] != mVertexAttrib0Vector[2] ||
        mFakeVertexAttrib0BufferObjectVector[3] != mVertexAttrib0Vector[3])
    {
        mFakeVertexAttrib0BufferStatus = whatDoesAttrib0Need;
        mFakeVertexAttrib0BufferObjectSize = dataSize;
        mFakeVertexAttrib0BufferObjectVector[0] = mVertexAttrib0Vector[0];
        mFakeVertexAttrib0BufferObjectVector[1] = mVertexAttrib0Vector[1];
        mFakeVertexAttrib0BufferObjectVector[2] = mVertexAttrib0Vector[2];
        mFakeVertexAttrib0BufferObjectVector[3] = mVertexAttrib0Vector[3];

        gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mFakeVertexAttrib0BufferObject);

        GetAndFlushUnderlyingGLErrors();

        if (mFakeVertexAttrib0BufferStatus == WebGLVertexAttrib0Status::EmulatedInitializedArray) {
            auto array = MakeUniqueFallible<GLfloat[]>(4 * vertexCount);
            if (!array) {
                ErrorOutOfMemory("Fake attrib0 array.");
                return false;
            }
            for(size_t i = 0; i < vertexCount; ++i) {
                array[4 * i + 0] = mVertexAttrib0Vector[0];
                array[4 * i + 1] = mVertexAttrib0Vector[1];
                array[4 * i + 2] = mVertexAttrib0Vector[2];
                array[4 * i + 3] = mVertexAttrib0Vector[3];
            }
            gl->fBufferData(LOCAL_GL_ARRAY_BUFFER, dataSize, array.get(), LOCAL_GL_DYNAMIC_DRAW);
        } else {
            gl->fBufferData(LOCAL_GL_ARRAY_BUFFER, dataSize, nullptr, LOCAL_GL_DYNAMIC_DRAW);
        }
        GLenum error = GetAndFlushUnderlyingGLErrors();

        gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mBoundArrayBuffer ? mBoundArrayBuffer->mGLName : 0);

        // note that we do this error checking and early return AFTER having restored the buffer binding above
        if (error) {
            ErrorOutOfMemory("Ran out of memory trying to construct a fake vertex attrib 0 array for a draw-operation "
                             "with %d vertices. Try reducing the number of vertices.", vertexCount);
            return false;
        }
    }

    gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mFakeVertexAttrib0BufferObject);
    gl->fVertexAttribPointer(0, 4, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, 0);

    return true;
}
bool
WebGLContext::ValidateBufferFetching(const char* info)
{
    MOZ_ASSERT(mCurrentProgram);
    // Note that mCurrentProgram->IsLinked() is NOT GUARANTEED.
    MOZ_ASSERT(mActiveProgramLinkInfo);

#ifdef DEBUG
    GLint currentProgram = 0;
    MakeContextCurrent();
    gl->fGetIntegerv(LOCAL_GL_CURRENT_PROGRAM, &currentProgram);
    MOZ_ASSERT(GLuint(currentProgram) == mCurrentProgram->mGLName,
               "WebGL: current program doesn't agree with GL state");
#endif

    if (mBufferFetchingIsVerified)
        return true;

    bool hasPerVertex = false;
    uint32_t maxVertices = UINT32_MAX;
    uint32_t maxInstances = UINT32_MAX;
    uint32_t attribs = mBoundVertexArray->mAttribs.Length();

    for (uint32_t i = 0; i < attribs; ++i) {
        const WebGLVertexAttribData& vd = mBoundVertexArray->mAttribs[i];

        // If the attrib array isn't enabled, there's nothing to check;
        // it's a static value.
        if (!vd.enabled)
            continue;

        if (vd.buf == nullptr) {
            ErrorInvalidOperation("%s: no VBO bound to enabled vertex attrib index %d!", info, i);
            return false;
        }

        // If the attrib is not in use, then we don't have to validate
        // it, just need to make sure that the binding is non-null.
        if (!mActiveProgramLinkInfo->HasActiveAttrib(i))
            continue;

        // the base offset
        CheckedUint32 checked_byteLength = CheckedUint32(vd.buf->ByteLength()) - vd.byteOffset;
        CheckedUint32 checked_sizeOfLastElement = CheckedUint32(vd.componentSize()) * vd.size;

        if (!checked_byteLength.isValid() ||
            !checked_sizeOfLastElement.isValid())
        {
            ErrorInvalidOperation("%s: integer overflow occured while checking vertex attrib %d", info, i);
            return false;
        }

        if (checked_byteLength.value() < checked_sizeOfLastElement.value()) {
            maxVertices = 0;
            maxInstances = 0;
            break;
        }

        CheckedUint32 checked_maxAllowedCount = ((checked_byteLength - checked_sizeOfLastElement) / vd.actualStride()) + 1;

        if (!checked_maxAllowedCount.isValid()) {
            ErrorInvalidOperation("%s: integer overflow occured while checking vertex attrib %d", info, i);
            return false;
        }

        if (vd.divisor == 0) {
            maxVertices = std::min(maxVertices, checked_maxAllowedCount.value());
            hasPerVertex = true;
        } else {
            CheckedUint32 checked_curMaxInstances = checked_maxAllowedCount * vd.divisor;

            uint32_t curMaxInstances = UINT32_MAX;
            // If this isn't valid, it's because we overflowed our
            // uint32 above. Just leave this as UINT32_MAX, since
            // sizeof(uint32) becomes our limiting factor.
            if (checked_curMaxInstances.isValid()) {
                curMaxInstances = checked_curMaxInstances.value();
            }

            maxInstances = std::min(maxInstances, curMaxInstances);
        }
    }

    mBufferFetchingIsVerified = true;
    mBufferFetchingHasPerVertex = hasPerVertex;
    mMaxFetchedVertices = maxVertices;
    mMaxFetchedInstances = maxInstances;

    return true;
}
bool
WebGLContext::DrawElements_check(GLsizei count, GLenum type,
                                 WebGLintptr byteOffset, GLsizei primcount,
                                 const char* info, GLuint* out_upperBound)
{
    if (count < 0 || byteOffset < 0) {
        ErrorInvalidValue("%s: negative count or offset", info);
        return false;
    }

    if (primcount < 0) {
        ErrorInvalidValue("%s: negative primcount", info);
        return false;
    }

    if (!ValidateStencilParamsForDrawCall()) {
        return false;
    }

    // If count is 0, there's nothing to do.
    if (count == 0 || primcount == 0)
        return false;

    uint8_t bytesPerElem = 0;
    switch (type) {
    case LOCAL_GL_UNSIGNED_BYTE:
        bytesPerElem = 1;
        break;

    case LOCAL_GL_UNSIGNED_SHORT:
        bytesPerElem = 2;
        break;

    case LOCAL_GL_UNSIGNED_INT:
        if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::OES_element_index_uint)) {
            bytesPerElem = 4;
        }
        break;
    }

    if (!bytesPerElem) {
        ErrorInvalidEnum("%s: Invalid `type`: 0x%04x", info, type);
        return false;
    }

    if (byteOffset % bytesPerElem != 0) {
        ErrorInvalidOperation("%s: `byteOffset` must be a multiple of the size of `type`",
                              info);
        return false;
    }

    const GLsizei first = byteOffset / bytesPerElem;
    const CheckedUint32 checked_byteCount = bytesPerElem * CheckedUint32(count);

    if (!checked_byteCount.isValid()) {
        ErrorInvalidValue("%s: overflow in byteCount", info);
        return false;
    }

    // Any checks below this depend on a program being available.
    if (!mCurrentProgram) {
        ErrorInvalidOperation("%s: null CURRENT_PROGRAM", info);
        return false;
    }

    if (!mBoundVertexArray->mElementArrayBuffer) {
        ErrorInvalidOperation("%s: must have element array buffer binding", info);
        return false;
    }

    WebGLBuffer& elemArrayBuffer = *mBoundVertexArray->mElementArrayBuffer;

    if (!elemArrayBuffer.ByteLength()) {
        ErrorInvalidOperation("%s: bound element array buffer doesn't have any data", info);
        return false;
    }

    CheckedInt<GLsizei> checked_neededByteCount = checked_byteCount.toChecked<GLsizei>() + byteOffset;

    if (!checked_neededByteCount.isValid()) {
        ErrorInvalidOperation("%s: overflow in byteOffset+byteCount", info);
        return false;
    }

    if (uint32_t(checked_neededByteCount.value()) > elemArrayBuffer.ByteLength()) {
        ErrorInvalidOperation("%s: bound element array buffer is too small for given count and offset", info);
        return false;
    }

    if (!ValidateBufferFetching(info))
        return false;

    if (!mMaxFetchedVertices ||
        !elemArrayBuffer.Validate(type, mMaxFetchedVertices - 1, first, count, out_upperBound))
    {
        ErrorInvalidOperation(
                              "%s: bound vertex attribute buffers do not have sufficient "
                              "size for given indices from the bound element array", info);
        return false;
    }

    if (uint32_t(primcount) > mMaxFetchedInstances) {
        ErrorInvalidOperation("%s: bound instance attribute buffers do not have sufficient size for given primcount", info);
        return false;
    }

    // Bug 1008310 - Check if buffer has been used with a different previous type
    if (elemArrayBuffer.IsElementArrayUsedWithMultipleTypes()) {
        GenerateWarning("%s: bound element array buffer previously used with a type other than "
                        "%s, this will affect performance.",
                        info,
                        WebGLContext::EnumName(type));
    }

    MOZ_ASSERT(gl->IsCurrent());

    if (mBoundDrawFramebuffer) {
        if (!mBoundDrawFramebuffer->ValidateAndInitAttachments(info))
            return false;
    } else {
        ClearBackbufferIfNeeded();
    }

    if (!DoFakeVertexAttrib0(mMaxFetchedVertices)) {
        return false;
    }

    return true;
}
Example #11
0
bool SkeletonState::DecodeFisbone(ogg_packet* aPacket)
{
  if (aPacket->bytes < static_cast<long>(FISBONE_MSG_FIELDS_OFFSET + 4)) {
    return false;
  }
  uint32_t offsetMsgField = LittleEndian::readUint32(aPacket->packet + FISBONE_MSG_FIELDS_OFFSET);

  if (aPacket->bytes < static_cast<long>(FISBONE_SERIALNO_OFFSET + 4)) {
      return false;
  }
  uint32_t serialno = LittleEndian::readUint32(aPacket->packet + FISBONE_SERIALNO_OFFSET);

  CheckedUint32 checked_fields_pos = CheckedUint32(FISBONE_MSG_FIELDS_OFFSET) + offsetMsgField;
  if (!checked_fields_pos.isValid() ||
      aPacket->bytes < static_cast<int64_t>(checked_fields_pos.value())) {
    return false;
  }
  int64_t msgLength = aPacket->bytes - checked_fields_pos.value();
  char* msgProbe = (char*)aPacket->packet + checked_fields_pos.value();
  char* msgHead = msgProbe;
  nsAutoPtr<MessageField> field(new MessageField());

  const static FieldPatternType kFieldTypeMaps[] = {
      {"Content-Type:", eContentType},
      {"Role:", eRole},
      {"Name:", eName},
      {"Language:", eLanguage},
      {"Title:", eTitle},
      {"Display-hint:", eDisplayHint},
      {"Altitude:", eAltitude},
      {"TrackOrder:", eTrackOrder},
      {"Track dependencies:", eTrackDependencies}
  };

  bool isContentTypeParsed = false;
  while (msgLength > 1) {
    if (*msgProbe == '\r' && *(msgProbe+1) == '\n') {
      nsAutoCString strMsg(msgHead, msgProbe-msgHead);
      for (size_t i = 0; i < ArrayLength(kFieldTypeMaps); i++) {
        if (strMsg.Find(kFieldTypeMaps[i].mPatternToRecognize) != -1) {
          // The content of message header fields follows [RFC2822], and the
          // mandatory message field must be encoded in US-ASCII, others
          // must be be encoded in UTF-8. "Content-Type" must come first
          // for all of message header fields.
          // See http://svn.annodex.net/standards/draft-pfeiffer-oggskeleton-current.txt.
          if (i != 0 && !isContentTypeParsed) {
            return false;
          }

          if ((i == 0 && IsASCII(strMsg)) || (i != 0 && IsUTF8(strMsg))) {
            EMsgHeaderType eHeaderType = kFieldTypeMaps[i].mMsgHeaderType;
            if (!field->mValuesStore.Contains(eHeaderType)) {
              uint32_t nameLen = strlen(kFieldTypeMaps[i].mPatternToRecognize);
              field->mValuesStore.Put(eHeaderType, new nsCString(msgHead+nameLen,
                                                                 msgProbe-msgHead-nameLen));
            }
            isContentTypeParsed = i==0 ? true : isContentTypeParsed;
          }
          break;
        }
      }
      msgProbe += 2;
      msgLength -= 2;
      msgHead = msgProbe;
      continue;
    }
    msgLength--;
    msgProbe++;
  };

  if (!mMsgFieldStore.Contains(serialno)) {
    mMsgFieldStore.Put(serialno, field.forget());
  } else {
    return false;
  }

  return true;
}
Example #12
0
nsresult nsRawReader::ReadMetadata(nsVideoInfo* aInfo,
                                   nsHTMLMediaElement::MetadataTags** aTags)
{
  NS_ASSERTION(mDecoder->OnDecodeThread(),
               "Should be on decode thread.");

  MediaResource* resource = mDecoder->GetResource();
  NS_ASSERTION(resource, "Decoder has no media resource");

  if (!ReadFromResource(resource, reinterpret_cast<uint8_t*>(&mMetadata),
                        sizeof(mMetadata)))
    return NS_ERROR_FAILURE;

  // Validate the header
  if (!(mMetadata.headerPacketID == 0 /* Packet ID of 0 for the header*/ &&
        mMetadata.codecID == RAW_ID /* "YUV" */ &&
        mMetadata.majorVersion == 0 &&
        mMetadata.minorVersion == 1))
    return NS_ERROR_FAILURE;

  CheckedUint32 dummy = CheckedUint32(static_cast<uint32_t>(mMetadata.frameWidth)) *
                          static_cast<uint32_t>(mMetadata.frameHeight);
  NS_ENSURE_TRUE(dummy.isValid(), NS_ERROR_FAILURE);

  if (mMetadata.aspectDenominator == 0 ||
      mMetadata.framerateDenominator == 0)
    return NS_ERROR_FAILURE; // Invalid data

  // Determine and verify frame display size.
  float pixelAspectRatio = static_cast<float>(mMetadata.aspectNumerator) / 
                            mMetadata.aspectDenominator;
  nsIntSize display(mMetadata.frameWidth, mMetadata.frameHeight);
  ScaleDisplayByAspectRatio(display, pixelAspectRatio);
  mPicture = nsIntRect(0, 0, mMetadata.frameWidth, mMetadata.frameHeight);
  nsIntSize frameSize(mMetadata.frameWidth, mMetadata.frameHeight);
  if (!nsVideoInfo::ValidateVideoRegion(frameSize, mPicture, display)) {
    // Video track's frame sizes will overflow. Fail.
    return NS_ERROR_FAILURE;
  }

  mInfo.mHasVideo = true;
  mInfo.mHasAudio = false;
  mInfo.mDisplay = display;

  mFrameRate = static_cast<float>(mMetadata.framerateNumerator) /
               mMetadata.framerateDenominator;

  // Make some sanity checks
  if (mFrameRate > 45 ||
      mFrameRate == 0 ||
      pixelAspectRatio == 0 ||
      mMetadata.frameWidth > 2000 ||
      mMetadata.frameHeight > 2000 ||
      mMetadata.chromaChannelBpp != 4 ||
      mMetadata.lumaChannelBpp != 8 ||
      mMetadata.colorspace != 1 /* 4:2:0 */)
    return NS_ERROR_FAILURE;

  mFrameSize = mMetadata.frameWidth * mMetadata.frameHeight *
    (mMetadata.lumaChannelBpp + mMetadata.chromaChannelBpp) / 8.0 +
    sizeof(nsRawPacketHeader);

  int64_t length = resource->GetLength();
  if (length != -1) {
    mozilla::ReentrantMonitorAutoEnter autoMonitor(mDecoder->GetReentrantMonitor());
    mDecoder->GetStateMachine()->SetDuration(USECS_PER_S *
                                           (length - sizeof(nsRawVideoHeader)) /
                                           (mFrameSize * mFrameRate));
  }

  *aInfo = mInfo;

  *aTags = nullptr;

  return NS_OK;
}