void WebGLContext::BindVertexArray(WebGLVertexArray* array) { if (IsContextLost()) return; if (!ValidateObjectAllowDeletedOrNull("bindVertexArrayObject", array)) return; if (array && array->IsDeleted()) { /* http://www.khronos.org/registry/gles/extensions/OES/OES_vertex_array_object.txt * BindVertexArrayOES fails and an INVALID_OPERATION error is * generated if array is not a name returned from a previous call to * GenVertexArraysOES, or if such a name has since been deleted with * DeleteVertexArraysOES */ ErrorInvalidOperation("bindVertexArray: can't bind a deleted array!"); return; } InvalidateBufferFetching(); MakeContextCurrent(); if (array == nullptr) { array = mDefaultVertexArray; } array->BindVertexArray(); MOZ_ASSERT(mBoundVertexArray == array); }
void WebGLContext::VertexAttribPointer(GLuint index, GLint size, GLenum type, WebGLboolean normalized, GLsizei stride, WebGLintptr byteOffset) { if (IsContextLost()) return; if (!ValidateAttribIndex(index, "vertexAttribPointer")) return; if (!ValidateAttribPointer(false, index, size, type, normalized, stride, byteOffset, "vertexAttribPointer")) return; MOZ_ASSERT(mBoundVertexArray); InvalidateBufferFetching(); /* XXX make work with bufferSubData & heterogeneous types if (type != mBoundArrayBuffer->GLType()) return ErrorInvalidOperation("vertexAttribPointer: type must match bound VBO type: %d != %d", type, mBoundArrayBuffer->GLType()); */ MakeContextCurrent(); gl->fVertexAttribPointer(index, size, type, normalized, stride, reinterpret_cast<void*>(byteOffset)); WebGLVertexAttribData& vd = mBoundVertexArray->mAttribs[index]; const bool integerFunc = false; vd.VertexAttribPointer(integerFunc, mBoundArrayBuffer, size, type, normalized, stride, byteOffset); }
void WebGL2Context::VertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset) { if (IsContextLost()) return; if (!ValidateAttribIndex(index, "vertexAttribIPointer")) return; if (!ValidateAttribPointer(true, index, size, type, LOCAL_GL_FALSE, stride, offset, "vertexAttribIPointer")) { return; } MOZ_ASSERT(mBoundVertexArray); mBoundVertexArray->EnsureAttrib(index); InvalidateBufferFetching(); WebGLVertexAttribData& vd = mBoundVertexArray->mAttribs[index]; vd.buf = mBoundArrayBuffer; vd.stride = stride; vd.size = size; vd.byteOffset = offset; vd.type = type; vd.normalized = false; vd.integer = true; MakeContextCurrent(); gl->fVertexAttribIPointer(index, size, type, stride, reinterpret_cast<void*>(offset)); }
void WebGLContext::BindVertexArray(WebGLVertexArray* array) { if (IsContextLost()) return; if (array && !ValidateObject("bindVertexArrayObject", *array)) return; InvalidateBufferFetching(); MakeContextCurrent(); if (mBoundVertexArray) { mBoundVertexArray->AddBufferBindCounts(-1); } if (array == nullptr) { array = mDefaultVertexArray; } array->BindVertexArray(); MOZ_ASSERT(mBoundVertexArray == array); if (mBoundVertexArray) { mBoundVertexArray->AddBufferBindCounts(+1); } }
void WebGLContext::EnableVertexAttribArray(GLuint index) { if (IsContextLost()) return; if (!ValidateAttribIndex(index, "enableVertexAttribArray")) return; MakeContextCurrent(); InvalidateBufferFetching(); gl->fEnableVertexAttribArray(index); MOZ_ASSERT(mBoundVertexArray); mBoundVertexArray->mAttribs[index].mEnabled = true; }
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 WebGLContext::DisableVertexAttribArray(GLuint index) { if (IsContextLost()) return; if (!ValidateAttribIndex(index, "disableVertexAttribArray")) return; MakeContextCurrent(); InvalidateBufferFetching(); if (index || !gl->IsCompatibilityProfile()) { gl->fDisableVertexAttribArray(index); } MOZ_ASSERT(mBoundVertexArray); mBoundVertexArray->mAttribs[index].mEnabled = false; }
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"); }
void WebGLContext::VertexAttribDivisor(GLuint index, GLuint divisor) { if (IsContextLost()) return; if (!ValidateAttribIndex(index, "vertexAttribDivisor")) return; MOZ_ASSERT(mBoundVertexArray); WebGLVertexAttribData& vd = mBoundVertexArray->mAttribs[index]; vd.mDivisor = divisor; InvalidateBufferFetching(); MakeContextCurrent(); gl->fVertexAttribDivisor(index, divisor); }
void WebGLContext::VertexAttribAnyPointer(const char* funcName, bool isFuncInt, GLuint index, GLint size, GLenum type, bool normalized, GLsizei stride, WebGLintptr byteOffset) { if (IsContextLost()) return; if (!ValidateAttribIndex(index, funcName)) return; //// if (size < 1 || size > 4) { ErrorInvalidValue("%s: invalid element size", funcName); return; } // see WebGL spec section 6.6 "Vertex Attribute Data Stride" if (stride < 0 || stride > 255) { ErrorInvalidValue("%s: negative or too large stride", funcName); return; } if (byteOffset < 0) { ErrorInvalidValue("%s: negative offset", funcName); return; } //// bool isTypeValid = true; uint8_t typeAlignment; switch (type) { // WebGL 1: case LOCAL_GL_BYTE: case LOCAL_GL_UNSIGNED_BYTE: typeAlignment = 1; break; case LOCAL_GL_SHORT: case LOCAL_GL_UNSIGNED_SHORT: typeAlignment = 2; break; case LOCAL_GL_FLOAT: if (isFuncInt) { isTypeValid = false; } typeAlignment = 4; break; // WebGL 2: case LOCAL_GL_INT: case LOCAL_GL_UNSIGNED_INT: if (!IsWebGL2()) { isTypeValid = false; } typeAlignment = 4; break; case LOCAL_GL_HALF_FLOAT: if (isFuncInt || !IsWebGL2()) { isTypeValid = false; } typeAlignment = 2; break; case LOCAL_GL_FIXED: if (isFuncInt || !IsWebGL2()) { isTypeValid = false; } typeAlignment = 4; break; case LOCAL_GL_INT_2_10_10_10_REV: case LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV: if (isFuncInt || !IsWebGL2()) { isTypeValid = false; break; } if (size != 4) { ErrorInvalidOperation("%s: size must be 4 for this type.", funcName); return; } typeAlignment = 4; break; default: isTypeValid = false; break; } if (!isTypeValid) { ErrorInvalidEnumArg(funcName, "type", type); return; } //// // `alignment` should always be a power of two. MOZ_ASSERT(IsPowerOfTwo(typeAlignment)); const GLsizei typeAlignmentMask = typeAlignment - 1; if (stride & typeAlignmentMask || byteOffset & typeAlignmentMask) { ErrorInvalidOperation("%s: `stride` and `byteOffset` must satisfy the alignment" " requirement of `type`.", funcName); return; } //// const auto& buffer = mBoundArrayBuffer; if (!buffer && byteOffset) { ErrorInvalidOperation("%s: If ARRAY_BUFFER is null, byteOffset must be zero.", funcName); return; } //// gl->MakeCurrent(); if (isFuncInt) { gl->fVertexAttribIPointer(index, size, type, stride, reinterpret_cast<void*>(byteOffset)); } else { gl->fVertexAttribPointer(index, size, type, normalized, stride, reinterpret_cast<void*>(byteOffset)); } WebGLVertexAttribData& vd = mBoundVertexArray->mAttribs[index]; vd.VertexAttribPointer(isFuncInt, buffer, size, type, normalized, stride, byteOffset); InvalidateBufferFetching(); }