예제 #1
0
GLenum
WebGLContext::CheckedBufferData(GLenum target, GLsizeiptr size,
                                const GLvoid* data, GLenum usage)
{
#ifdef XP_MACOSX
    // bug 790879
    if (gl->WorkAroundDriverBugs() &&
        int64_t(size) > INT32_MAX) // cast avoids a potential always-true warning on 32bit
    {
        GenerateWarning("Rejecting valid bufferData call with size %lu to avoid"
                        " a Mac bug", size);
        return LOCAL_GL_INVALID_VALUE;
    }
#endif

    WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target);
    WebGLBuffer* boundBuffer = bufferSlot.get();
    MOZ_ASSERT(boundBuffer, "No buffer bound for this target.");

    bool sizeChanges = uint32_t(size) != boundBuffer->ByteLength();
    if (sizeChanges) {
        GetAndFlushUnderlyingGLErrors();
        gl->fBufferData(target, size, data, usage);
        GLenum error = GetAndFlushUnderlyingGLErrors();
        return error;
    } else {
        gl->fBufferData(target, size, data, usage);
        return LOCAL_GL_NO_ERROR;
    }
}
예제 #2
0
void
WebGLContext::UpdateBoundBuffer(GLenum target, WebGLBuffer* buffer)
{
    WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target);
    bufferSlot = buffer;

    if (!buffer)
        return;

    buffer->BindTo(target);
}
예제 #3
0
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());
}
예제 #4
0
void
WebGLContext::BufferData(GLenum target, WebGLsizeiptr size, GLenum usage)
{
    if (IsContextLost())
        return;

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

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

    if (size < 0)
        return ErrorInvalidValue("bufferData: negative size");

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

    // careful: WebGLsizeiptr is always 64-bit, but GLsizeiptr is like intptr_t.
    if (!CheckedInt<GLsizeiptr>(size).isValid())
        return ErrorOutOfMemory("bufferData: bad size");

    WebGLBuffer* boundBuffer = bufferSlot.get();

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

    UniquePtr<uint8_t> zeroBuffer((uint8_t*)calloc(size, 1));
    if (!zeroBuffer)
        return ErrorOutOfMemory("bufferData: out of memory");

    MakeContextCurrent();
    InvalidateBufferFetching();

    GLenum error = CheckedBufferData(target, size, zeroBuffer.get(), usage);

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

    boundBuffer->SetByteLength(size);
    if (!boundBuffer->ElementArrayCacheBufferData(nullptr, size)) {
        return ErrorOutOfMemory("bufferData: out of memory");
    }
}
예제 #5
0
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");
}
예제 #6
0
void
WebGL2Context::CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
                                 GLintptr readOffset, GLintptr writeOffset,
                                 GLsizeiptr size)
{
    if (IsContextLost())
        return;

    if (!ValidateBufferTarget(readTarget, "copyBufferSubData") ||
            !ValidateBufferTarget(writeTarget, "copyBufferSubData"))
    {
        return;
    }

    const WebGLRefPtr<WebGLBuffer>& readBufferSlot = GetBufferSlotByTarget(readTarget);
    const WebGLRefPtr<WebGLBuffer>& writeBufferSlot = GetBufferSlotByTarget(writeTarget);
    if (!readBufferSlot || !writeBufferSlot)
        return;

    const WebGLBuffer* readBuffer = readBufferSlot.get();
    if (!readBuffer)
        return ErrorInvalidOperation("copyBufferSubData: No buffer bound to readTarget");

    WebGLBuffer* writeBuffer = writeBufferSlot.get();
    if (!writeBuffer)
        return ErrorInvalidOperation("copyBufferSubData: No buffer bound to writeTarget");

    if (!ValidateDataOffsetSize(readOffset, size, readBuffer->ByteLength(),
                                "copyBufferSubData"))
    {
        return;
    }

    if (!ValidateDataOffsetSize(writeOffset, size, writeBuffer->ByteLength(),
                                "copyBufferSubData"))
    {
        return;
    }

    if (readTarget == writeTarget &&
            !ValidateDataRanges(readOffset, writeOffset, size, "copyBufferSubData"))
    {
        return;
    }

    WebGLBuffer::Kind readType = readBuffer->Content();
    WebGLBuffer::Kind writeType = writeBuffer->Content();

    if (readType != WebGLBuffer::Kind::Undefined &&
            writeType != WebGLBuffer::Kind::Undefined &&
            writeType != readType)
    {
        ErrorInvalidOperation("copyBufferSubData: Can't copy %s data to %s data",
                              (readType == WebGLBuffer::Kind::OtherData) ? "other" : "element",
                              (writeType == WebGLBuffer::Kind::OtherData) ? "other" : "element");
        return;
    }

    WebGLContextUnchecked::CopyBufferSubData(readTarget, writeTarget, readOffset,
            writeOffset, size);

    if (writeType == WebGLBuffer::Kind::Undefined) {
        writeBuffer->BindTo(
            (readType == WebGLBuffer::Kind::OtherData) ? LOCAL_GL_ARRAY_BUFFER
            : LOCAL_GL_ELEMENT_ARRAY_BUFFER);
    }
}
예제 #7
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.LengthAllowShared();
    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.LengthAllowShared(), LOCAL_GL_MAP_READ_BIT);
    // Warning: Possibly shared memory.  See bug 1225033.
    memcpy(data.DataAllowShared(), ptr, data.LengthAllowShared());
    gl->fUnmapBuffer(target);

    if (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER && currentTF) {
        BindTransformFeedback(LOCAL_GL_TRANSFORM_FEEDBACK, currentTF);
    }
}