void
WebGLContext::BufferSubDataT(GLenum target,
                             WebGLsizeiptr byteOffset,
                             const BufferT& data)
{
    if (IsContextLost())
        return;

    if (!ValidateBufferTarget(target, "bufferSubData"))
        return;

    WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target);

    if (byteOffset < 0)
        return ErrorInvalidValue("bufferSubData: negative offset");

    WebGLBuffer* boundBuffer = bufferSlot.get();
    if (!boundBuffer)
        return ErrorInvalidOperation("bufferData: no buffer bound!");

    data.ComputeLengthAndData();

    CheckedInt<WebGLsizeiptr> checked_neededByteLength =
        CheckedInt<WebGLsizeiptr>(byteOffset) + data.Length();

    if (!checked_neededByteLength.isValid()) {
        ErrorInvalidValue("bufferSubData: Integer overflow computing the needed"
                          " byte length.");
        return;
    }

    if (checked_neededByteLength.value() > boundBuffer->ByteLength()) {
        ErrorInvalidValue("bufferSubData: Not enough data. Operation requires"
                          " %d bytes, but buffer only has %d bytes.",
                          checked_neededByteLength.value(),
                          boundBuffer->ByteLength());
        return;
    }

    boundBuffer->ElementArrayCacheBufferSubData(byteOffset, data.Data(),
                                                data.Length());

    MakeContextCurrent();
    gl->fBufferSubData(target, byteOffset, data.Length(), data.Data());
}
void
WebGLContext::BufferDataT(GLenum target,
                          const BufferT& data,
                          GLenum usage)
{
    if (IsContextLost())
        return;

    if (!ValidateBufferTarget(target, "bufferData"))
        return;

    const WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target);

    data.ComputeLengthAndData();

    // Careful: data.Length() could conceivably be any uint32_t, but GLsizeiptr
    // is like intptr_t.
    if (!CheckedInt<GLsizeiptr>(data.Length()).isValid())
        return ErrorOutOfMemory("bufferData: bad size");

    if (!ValidateBufferUsageEnum(usage, "bufferData: usage"))
        return;

    WebGLBuffer* boundBuffer = bufferSlot.get();

    if (!boundBuffer)
        return ErrorInvalidOperation("bufferData: no buffer bound!");

    MakeContextCurrent();
    InvalidateBufferFetching();

    GLenum error = CheckedBufferData(target, data.Length(), data.Data(), usage);

    if (error) {
        GenerateWarning("bufferData generated error %s", ErrorName(error));
        return;
    }

    boundBuffer->SetByteLength(data.Length());
    if (!boundBuffer->ElementArrayCacheBufferData(data.Data(), data.Length()))
        return ErrorOutOfMemory("bufferData: out of memory");
}
Esempio n. 3
0
void
WebGL2Context::GetBufferSubDataT(GLenum target, GLintptr offset, const BufferT& data)
{
    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");

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