void
WebGL2Context::SamplerParameteri(WebGLSampler* sampler, GLenum pname, GLint param)
{
    if (IsContextLost())
        return;

    if (!sampler || sampler->IsDeleted())
        return ErrorInvalidOperation("samplerParameteri: invalid sampler");

    if (!ValidateSamplerParameterParams(pname, WebGLIntOrFloat(param), "samplerParameteri"))
        return;

    WebGLContextUnchecked::SamplerParameteri(sampler, pname, param);
}
bool
WebGLContext::ValidateStencilParamsForDrawCall()
{
    const char msg[] = "%s set different front and back stencil %s. Drawing in"
                       " this configuration is not allowed.";

    if (mStencilRefFront != mStencilRefBack) {
        ErrorInvalidOperation(msg, "stencilFuncSeparate", "reference values");
        return false;
    }

    if (mStencilValueMaskFront != mStencilValueMaskBack) {
        ErrorInvalidOperation(msg, "stencilFuncSeparate", "value masks");
        return false;
    }

    if (mStencilWriteMaskFront != mStencilWriteMaskBack) {
        ErrorInvalidOperation(msg, "stencilMaskSeparate", "write masks");
        return false;
    }

    return true;
}
void
WebGL2Context::RenderbufferStorageMultisample(GLenum target, GLsizei samples,
                                              GLenum internalFormat,
                                              GLsizei width, GLsizei height)
{
  const char funcName[] = "renderbufferStorageMultisample";
  if (IsContextLost())
    return;

  //RenderbufferStorage_base(funcName, target, samples, internalFormat, width, height);

  ErrorInvalidOperation("%s: Multisampling is still under development, and is currently"
                        " disabled.", funcName);
}
Exemplo n.º 4
0
void
WebGLContext::BindBufferBase(GLenum target, GLuint index, WebGLBuffer* buffer)
{
    const char funcName[] = "bindBufferBase";
    if (IsContextLost())
        return;

    if (!ValidateObjectAllowDeletedOrNull(funcName, buffer))
        return;

    if (buffer && buffer->IsDeleted())
        return ErrorInvalidOperation("%s: Cannot bind a deleted object.", funcName);

    WebGLRefPtr<WebGLBuffer>* genericBinding;
    IndexedBufferBinding* indexedBinding;
    if (!ValidateIndexedBufferBinding(funcName, target, index, &genericBinding,
                                      &indexedBinding))
    {
        return;
    }

    if (buffer && !buffer->ValidateCanBindToTarget(funcName, target))
        return;

    ////

    gl->MakeCurrent();
    gl->fBindBufferBase(target, index, buffer ? buffer->mGLName : 0);

    ////

    *genericBinding = buffer;
    indexedBinding->mBufferBinding = buffer;
    indexedBinding->mRangeStart = 0;
    indexedBinding->mRangeSize = 0;

    if (buffer) {
        buffer->SetContentAfterBind(target);
    }

    switch (target) {
    case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
        mBoundTransformFeedback->OnIndexedBindingsChanged();
        break;
    case LOCAL_GL_UNIFORM:
        OnUBIndexedBindingsChanged();
        break;
    }
}
Exemplo n.º 5
0
void WebGLContext::BeginQuery(GLenum target, WebGLQuery& query) {
  const FuncScope funcScope(*this, "beginQuery");
  if (IsContextLost()) return;

  if (!ValidateObject("query", query)) return;

  const auto& slot = ValidateQuerySlotByTarget(target);
  if (!slot) return;

  if (*slot) return ErrorInvalidOperation("Query target already active.");

  ////

  query.BeginQuery(target, *slot);
}
void
WebGL2Context::BeginTransformFeedback(GLenum primitiveMode)
{
    if (IsContextLost())
        return;

    WebGLTransformFeedback* tf = mBoundTransformFeedback;
    MOZ_ASSERT(tf);
    if (!tf)
        return;

    if (tf->mIsActive)
        return ErrorInvalidOperation("beginTransformFeedback: transform feedback is active");

    const GLenum mode = tf->mMode;
    if (mode != LOCAL_GL_POINTS && mode != LOCAL_GL_LINES && mode != LOCAL_GL_TRIANGLES)
        return ErrorInvalidEnum("beginTransformFeedback: primitive must be one of POINTS, LINES, or TRIANGLES");

    // TODO:
    // GL_INVALID_OPERATION is generated by glBeginTransformFeedback
    // if any binding point used in transform feedback mode does not
    // have a buffer object bound. In interleaved mode, only the first
    // buffer object binding point is ever written to.

    // GL_INVALID_OPERATION is generated by glBeginTransformFeedback
    // if no binding points would be used, either because no program
    // object is active of because the active program object has
    // specified no varying variables to record.
    if (!mCurrentProgram)
        return ErrorInvalidOperation("beginTransformFeedback: no program is active");

    MakeContextCurrent();
    gl->fBeginTransformFeedback(primitiveMode);
    tf->mIsActive = true;
    tf->mIsPaused = false;
}
Exemplo n.º 7
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());
}
Exemplo n.º 8
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");
    }
}
void
WebGL2Context::DeleteTransformFeedback(WebGLTransformFeedback* tf)
{
    const char funcName[] = "deleteTransformFeedback";
    if (!ValidateDeleteObject(funcName, tf))
        return;

    if (tf->mIsActive) {
        ErrorInvalidOperation("%s: Cannot delete active transform feedbacks.", funcName);
        return;
    }

    if (mBoundTransformFeedback == tf) {
        BindTransformFeedback(LOCAL_GL_TRANSFORM_FEEDBACK, nullptr);
    }

    tf->RequestDelete();
}
Exemplo n.º 10
0
void
WebGL2Context::SamplerParameterfv(WebGLSampler* sampler, GLenum pname, const dom::Sequence<GLfloat>& param)
{
    if (IsContextLost())
        return;

    if (!sampler || sampler->IsDeleted())
        return ErrorInvalidOperation("samplerParameterfv: invalid sampler");

    if (param.Length() < 1)
        return /* TODO(djg): Error message */;

    /* TODO(djg): All of these calls in ES3 only take 1 param */
    if (!ValidateSamplerParameterParams(pname, WebGLIntOrFloat(param[0]), "samplerParameterfv"))
        return;

    WebGLContextUnchecked::SamplerParameterfv(sampler, pname, param.Elements());
}
void
WebGL2Context::ResumeTransformFeedback()
{
    if (IsContextLost())
        return;

    WebGLTransformFeedback* tf = mBoundTransformFeedback;
    MOZ_ASSERT(tf);
    if (!tf)
        return;

    if (!tf->mIsActive || !tf->mIsPaused)
        return ErrorInvalidOperation("resumeTransformFeedback: transform feedback is not active or is not paused");

    MakeContextCurrent();
    gl->fResumeTransformFeedback();
    tf->mIsPaused = false;
}
Exemplo n.º 12
0
WebGLBuffer*
WebGLContext::ValidateBufferSelection(const char* funcName, GLenum target)
{
    const auto& slot = ValidateBufferSlot(funcName, target);
    if (!slot)
        return nullptr;
    const auto& buffer = *slot;

    if (!buffer) {
        ErrorInvalidOperation("%s: Buffer for `target` is null.", funcName);
        return nullptr;
    }

    if (!ValidateForNonTransformFeedback(funcName, buffer.get()))
        return nullptr;

    return buffer.get();
}
Exemplo n.º 13
0
void
WebGL2Context::SamplerParameteriv(WebGLSampler* sampler, GLenum pname, const dom::Int32Array& param)
{
    if (IsContextLost())
        return;

    if (!sampler || sampler->IsDeleted())
        return ErrorInvalidOperation("samplerParameteriv: invalid sampler");

    param.ComputeLengthAndData();
    if (param.Length() < 1)
        return /* TODO(djg): Error message */;

    /* TODO(djg): All of these calls in ES3 only take 1 param */
    if (!ValidateSamplerParameterParams(pname, WebGLIntOrFloat(param.Data()[0]), "samplerParameteriv"))
        return;

    WebGLContextUnchecked::SamplerParameteriv(sampler, pname, param.Data());
}
Exemplo n.º 14
0
bool
WebGLContext::ValidateFramebufferAttachment(const WebGLFramebuffer* fb, GLenum attachment,
                                            const char* funcName,
                                            bool badColorAttachmentIsInvalidOp)
{
    if (!fb) {
        switch (attachment) {
        case LOCAL_GL_COLOR:
        case LOCAL_GL_DEPTH:
        case LOCAL_GL_STENCIL:
            return true;

        default:
            ErrorInvalidEnum("%s: attachment: invalid enum value 0x%x.",
                             funcName, attachment);
            return false;
        }
    }

    if (attachment == LOCAL_GL_DEPTH_ATTACHMENT ||
        attachment == LOCAL_GL_STENCIL_ATTACHMENT ||
        attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
    {
        return true;
    }

    if (attachment >= LOCAL_GL_COLOR_ATTACHMENT0 &&
        attachment <= LastColorAttachmentEnum())
    {
        return true;
    }

    if (badColorAttachmentIsInvalidOp &&
        attachment >= LOCAL_GL_COLOR_ATTACHMENT0)
    {
        const uint32_t offset = attachment - LOCAL_GL_COLOR_ATTACHMENT0;
        ErrorInvalidOperation("%s: Bad color attachment: COLOR_ATTACHMENT%u. (0x%04x)",
                              funcName, offset, attachment);
    } else {
        ErrorInvalidEnum("%s: attachment: Bad attachment 0x%x.", funcName, attachment);
    }
    return false;
}
Exemplo n.º 15
0
void
WebGL2Context::BindSampler(GLuint unit, WebGLSampler* sampler)
{
    if (IsContextLost())
        return;

    if (!ValidateObjectAllowDeletedOrNull("bindSampler", sampler))
        return;

    if (GLint(unit) >= mGLMaxTextureUnits)
        return ErrorInvalidValue("bindSampler: unit must be < %d", mGLMaxTextureUnits);

    if (sampler && sampler->IsDeleted())
        return ErrorInvalidOperation("bindSampler: binding deleted sampler");

    WebGLContextUnchecked::BindSampler(unit, sampler);

    mBoundSamplers[unit] = sampler;
}
void
WebGL2Context::EndQuery(GLenum target)
{
    if (IsContextLost())
        return;

    if (!ValidateQueryTarget(target, "endQuery"))
        return;

    WebGLRefPtr<WebGLQuery>& querySlot = GetQuerySlotByTarget(target);
    WebGLQuery* activeQuery = querySlot.get();

    if (!activeQuery || target != activeQuery->mType)
    {
        /* From GLES's EXT_occlusion_query_boolean:
         *     marks the end of the sequence of commands to be tracked for the
         *     query type given by <target>. The active query object for
         *     <target> is updated to indicate that query results are not
         *     available, and the active query object name for <target> is reset
         *     to zero. When the commands issued prior to EndQueryEXT have
         *     completed and a final query result is available, the query object
         *     active when EndQueryEXT is called is updated by the GL. The query
         *     object is updated to indicate that the query results are
         *     available and to contain the query result. If the active query
         *     object name for <target> is zero when EndQueryEXT is called, the
         *     error INVALID_OPERATION is generated.
         */
        ErrorInvalidOperation("endQuery: There is no active query of type %s.",
                              GetQueryTargetEnumString(target));
        return;
    }

    MakeContextCurrent();

    if (target == LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN) {
        gl->fEndQuery(LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
    } else {
        gl->fEndQuery(SimulateOcclusionQueryTarget(gl, target));
    }

    UpdateBoundQuery(target, nullptr);
    NS_DispatchToCurrentThread(new WebGLQuery::AvailableRunnable(activeQuery));
}
Exemplo n.º 17
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");
}
Exemplo n.º 18
0
bool WebGLContext::ValidateIndexedBufferBinding(
    GLenum target, GLuint index,
    WebGLRefPtr<WebGLBuffer>** const out_genericBinding,
    IndexedBufferBinding** const out_indexedBinding) {
  *out_genericBinding = ValidateBufferSlot(target);
  if (!*out_genericBinding) return false;

  *out_indexedBinding = ValidateIndexedBufferSlot(target, index);
  if (!*out_indexedBinding) return false;

  if (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER &&
      mBoundTransformFeedback->mIsActive) {
    ErrorInvalidOperation(
        "Cannot update indexed buffer bindings on active"
        " transform feedback objects.");
    return false;
  }

  return true;
}
void
WebGL2Context::PauseTransformFeedback()
{
    if (IsContextLost())
        return;

    WebGLTransformFeedback* tf = mBoundTransformFeedback;
    MOZ_ASSERT(tf);
    if (!tf)
        return;

    if (!tf->mIsActive || tf->mIsPaused) {
        return ErrorInvalidOperation("%s: transform feedback is not active or is paused",
                                     "pauseTransformFeedback");
    }

    MakeContextCurrent();
    gl->fPauseTransformFeedback();
    tf->mIsPaused = true;
}
Exemplo n.º 20
0
void
WebGLContext::EndQuery(GLenum target, const char* funcName)
{
    if (!funcName) {
        funcName = "endQuery";
    }

    if (IsContextLost())
        return;

    const auto& slot = ValidateQuerySlotByTarget(funcName, target);
    if (!slot)
        return;

    const auto& query = *slot;
    if (!query)
        return ErrorInvalidOperation("%s: Query target not active.", funcName);

    query->EndQuery();
}
Exemplo n.º 21
0
bool
WebGLContext::ValidateUniformLocation(WebGLUniformLocation* loc, const char* funcName)
{
    /* GLES 2.0.25, p38:
     *   If the value of location is -1, the Uniform* commands will silently
     *   ignore the data passed in, and the current uniform values will not be
     *   changed.
     */
    if (!loc)
        return false;

    if (!ValidateObject(funcName, loc))
        return false;

    if (!mCurrentProgram) {
        ErrorInvalidOperation("%s: No program is currently bound.", funcName);
        return false;
    }

    return loc->ValidateForProgram(mCurrentProgram, this, funcName);
}
void
WebGL2Context::EndTransformFeedback()
{
    if (IsContextLost())
        return;

    WebGLTransformFeedback* tf = mBoundTransformFeedback;
    MOZ_ASSERT(tf);

    if (!tf)
        return;

    if (!tf->mIsActive)
        return ErrorInvalidOperation("%s: transform feedback in not active",
                                     "endTransformFeedback");

    MakeContextCurrent();
    gl->fEndTransformFeedback();
    tf->mIsActive = false;
    tf->mIsPaused = false;
}
Exemplo n.º 23
0
bool
WebGLContext::DrawInstanced_check(const char* info)
{
    MOZ_ASSERT(IsWebGL2() ||
               IsExtensionEnabled(WebGLExtensionID::ANGLE_instanced_arrays));
    if (!mBufferFetchingHasPerVertex) {
        /* http://www.khronos.org/registry/gles/extensions/ANGLE/ANGLE_instanced_arrays.txt
         *  If all of the enabled vertex attribute arrays that are bound to active
         *  generic attributes in the program have a non-zero divisor, the draw
         *  call should return INVALID_OPERATION.
         *
         * NB: This also appears to apply to NV_instanced_arrays, though the
         * INVALID_OPERATION emission is not explicitly stated.
         * ARB_instanced_arrays does not have this restriction.
         */
        ErrorInvalidOperation("%s: at least one vertex attribute divisor should be 0", info);
        return false;
    }

    return true;
}
Exemplo n.º 24
0
already_AddRefed<WebGLSampler>
WebGL2Context::CreateSampler()
{
    const char funcName[] = "createSampler";

    if (IsContextLost())
        return nullptr;

    /*
    GLuint sampler;
    MakeContextCurrent();
    gl->fGenSamplers(1, &sampler);

    RefPtr<WebGLSampler> globj = new WebGLSampler(this, sampler);
    return globj.forget();
    */

    ErrorInvalidOperation("%s: Sampler objects are still under development, and are"
                          " currently disabled.",
                          funcName);
    return nullptr;
}
Exemplo n.º 25
0
bool
WebGLContext::ValidateBlendFuncEnumsCompatibility(GLenum sfactor,
                                                  GLenum dfactor,
                                                  const char* info)
{
    bool sfactorIsConstantColor = sfactor == LOCAL_GL_CONSTANT_COLOR ||
                                  sfactor == LOCAL_GL_ONE_MINUS_CONSTANT_COLOR;
    bool sfactorIsConstantAlpha = sfactor == LOCAL_GL_CONSTANT_ALPHA ||
                                  sfactor == LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA;
    bool dfactorIsConstantColor = dfactor == LOCAL_GL_CONSTANT_COLOR ||
                                  dfactor == LOCAL_GL_ONE_MINUS_CONSTANT_COLOR;
    bool dfactorIsConstantAlpha = dfactor == LOCAL_GL_CONSTANT_ALPHA ||
                                  dfactor == LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA;
    if ( (sfactorIsConstantColor && dfactorIsConstantAlpha) ||
         (dfactorIsConstantColor && sfactorIsConstantAlpha) )
    {
        ErrorInvalidOperation("%s are mutually incompatible, see section 6.8 in"
                              " the WebGL 1.0 spec", info);
        return false;
    }

    return true;
}
void
WebGL2Context::BindTransformFeedback(GLenum target, WebGLTransformFeedback* tf)
{
    const char funcName[] = "bindTransformFeedback";
    if (IsContextLost())
        return;

    if (target != LOCAL_GL_TRANSFORM_FEEDBACK)
        return ErrorInvalidEnum("%s: `target` must be TRANSFORM_FEEDBACK.", funcName);

    if (tf && !ValidateObject(funcName, *tf))
        return;

    if (mBoundTransformFeedback->mIsActive &&
        !mBoundTransformFeedback->mIsPaused)
    {
        ErrorInvalidOperation("%s: Currently bound transform feedback is active and not"
                              " paused.",
                              funcName);
        return;
    }

    ////

    if (mBoundTransformFeedback) {
        mBoundTransformFeedback->AddBufferBindCounts(-1);
    }

    mBoundTransformFeedback = (tf ? tf : mDefaultTransformFeedback);

    MakeContextCurrent();
    gl->fBindTransformFeedback(target, mBoundTransformFeedback->mGLName);

    if (mBoundTransformFeedback) {
        mBoundTransformFeedback->AddBufferBindCounts(+1);
    }
}
Exemplo n.º 27
0
void
WebGLContext::BeginQuery(GLenum target, WebGLQuery& query, const char* funcName)
{
    if (!funcName) {
        funcName = "beginQuery";
    }

    if (IsContextLost())
        return;

    if (!ValidateObject(funcName, query))
        return;

    const auto& slot = ValidateQuerySlotByTarget(funcName, target);
    if (!slot)
        return;

    if (*slot)
        return ErrorInvalidOperation("%s: Query target already active.", funcName);

    ////

    query.BeginQuery(target, *slot);
}
Exemplo n.º 28
0
bool
WebGL2Context::ValidateBufferTarget(GLenum target, const char* info)
{
    switch (target) {
    case LOCAL_GL_ARRAY_BUFFER:
    case LOCAL_GL_COPY_READ_BUFFER:
    case LOCAL_GL_COPY_WRITE_BUFFER:
    case LOCAL_GL_ELEMENT_ARRAY_BUFFER:
    case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
    case LOCAL_GL_UNIFORM_BUFFER:
        return true;

    case LOCAL_GL_PIXEL_PACK_BUFFER:
    case LOCAL_GL_PIXEL_UNPACK_BUFFER:
        ErrorInvalidOperation("%s: PBOs are still under development, and are currently"
                              " disabled.",
                              info);
        return false;

    default:
        ErrorInvalidEnumInfo(info, target);
        return false;
    }
}
Exemplo n.º 29
0
bool
WebGLContext::DrawElements_check(const char* funcName, GLenum mode, GLsizei vertCount,
                                 GLenum type, WebGLintptr byteOffset,
                                 GLsizei instanceCount)
{
    if (!ValidateDrawModeEnum(mode, funcName))
        return false;

    if (mBoundTransformFeedback &&
        mBoundTransformFeedback->mIsActive &&
        !mBoundTransformFeedback->mIsPaused)
    {
        ErrorInvalidOperation("%s: DrawElements* functions are incompatible with"
                              " transform feedback.",
                              funcName);
        return false;
    }

    if (!ValidateNonNegative(funcName, "vertCount", vertCount) ||
        !ValidateNonNegative(funcName, "byteOffset", byteOffset) ||
        !ValidateNonNegative(funcName, "instanceCount", instanceCount))
    {
        return false;
    }

    if (!ValidateStencilParamsForDrawCall())
        return false;

    if (!vertCount || !instanceCount)
        return false; // No error, just early out.

    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", funcName, type);
        return false;
    }

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

    ////

    if (IsWebGL2() && !gl->IsSupported(gl::GLFeature::prim_restart_fixed)) {
        MOZ_ASSERT(gl->IsSupported(gl::GLFeature::prim_restart));
        if (mPrimRestartTypeBytes != bytesPerElem) {
            mPrimRestartTypeBytes = bytesPerElem;

            const uint32_t ones = UINT32_MAX >> (32 - 8*mPrimRestartTypeBytes);
            gl->fEnable(LOCAL_GL_PRIMITIVE_RESTART);
            gl->fPrimitiveRestartIndex(ones);
        }
Exemplo n.º 30
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);
    }
}