michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "WebGLContext.h" michael@0: michael@0: #include "GLContext.h" michael@0: #include "mozilla/CheckedInt.h" michael@0: #include "WebGLBuffer.h" michael@0: #include "WebGLFramebuffer.h" michael@0: #include "WebGLProgram.h" michael@0: #include "WebGLRenderbuffer.h" michael@0: #include "WebGLShader.h" michael@0: #include "WebGLTexture.h" michael@0: #include "WebGLUniformInfo.h" michael@0: #include "WebGLVertexArray.h" michael@0: #include "WebGLVertexAttribData.h" michael@0: michael@0: using namespace mozilla; michael@0: using namespace dom; michael@0: michael@0: void michael@0: WebGLContext::VertexAttrib1f(GLuint index, GLfloat x0) michael@0: { michael@0: if (IsContextLost()) michael@0: return; michael@0: michael@0: MakeContextCurrent(); michael@0: michael@0: if (index) { michael@0: gl->fVertexAttrib1f(index, x0); michael@0: } else { michael@0: mVertexAttrib0Vector[0] = x0; michael@0: mVertexAttrib0Vector[1] = 0; michael@0: mVertexAttrib0Vector[2] = 0; michael@0: mVertexAttrib0Vector[3] = 1; michael@0: if (gl->IsGLES()) michael@0: gl->fVertexAttrib1f(index, x0); michael@0: } michael@0: } michael@0: michael@0: void michael@0: WebGLContext::VertexAttrib2f(GLuint index, GLfloat x0, GLfloat x1) michael@0: { michael@0: if (IsContextLost()) michael@0: return; michael@0: michael@0: MakeContextCurrent(); michael@0: michael@0: if (index) { michael@0: gl->fVertexAttrib2f(index, x0, x1); michael@0: } else { michael@0: mVertexAttrib0Vector[0] = x0; michael@0: mVertexAttrib0Vector[1] = x1; michael@0: mVertexAttrib0Vector[2] = 0; michael@0: mVertexAttrib0Vector[3] = 1; michael@0: if (gl->IsGLES()) michael@0: gl->fVertexAttrib2f(index, x0, x1); michael@0: } michael@0: } michael@0: michael@0: void michael@0: WebGLContext::VertexAttrib3f(GLuint index, GLfloat x0, GLfloat x1, GLfloat x2) michael@0: { michael@0: if (IsContextLost()) michael@0: return; michael@0: michael@0: MakeContextCurrent(); michael@0: michael@0: if (index) { michael@0: gl->fVertexAttrib3f(index, x0, x1, x2); michael@0: } else { michael@0: mVertexAttrib0Vector[0] = x0; michael@0: mVertexAttrib0Vector[1] = x1; michael@0: mVertexAttrib0Vector[2] = x2; michael@0: mVertexAttrib0Vector[3] = 1; michael@0: if (gl->IsGLES()) michael@0: gl->fVertexAttrib3f(index, x0, x1, x2); michael@0: } michael@0: } michael@0: michael@0: void michael@0: WebGLContext::VertexAttrib4f(GLuint index, GLfloat x0, GLfloat x1, michael@0: GLfloat x2, GLfloat x3) michael@0: { michael@0: if (IsContextLost()) michael@0: return; michael@0: michael@0: MakeContextCurrent(); michael@0: michael@0: if (index) { michael@0: gl->fVertexAttrib4f(index, x0, x1, x2, x3); michael@0: } else { michael@0: mVertexAttrib0Vector[0] = x0; michael@0: mVertexAttrib0Vector[1] = x1; michael@0: mVertexAttrib0Vector[2] = x2; michael@0: mVertexAttrib0Vector[3] = x3; michael@0: if (gl->IsGLES()) michael@0: gl->fVertexAttrib4f(index, x0, x1, x2, x3); michael@0: } michael@0: } michael@0: michael@0: michael@0: void michael@0: WebGLContext::VertexAttrib1fv_base(GLuint idx, uint32_t arrayLength, michael@0: const GLfloat* ptr) michael@0: { michael@0: if (!ValidateAttribArraySetter("VertexAttrib1fv", 1, arrayLength)) michael@0: return; michael@0: michael@0: MakeContextCurrent(); michael@0: if (idx) { michael@0: gl->fVertexAttrib1fv(idx, ptr); michael@0: } else { michael@0: mVertexAttrib0Vector[0] = ptr[0]; michael@0: mVertexAttrib0Vector[1] = GLfloat(0); michael@0: mVertexAttrib0Vector[2] = GLfloat(0); michael@0: mVertexAttrib0Vector[3] = GLfloat(1); michael@0: if (gl->IsGLES()) michael@0: gl->fVertexAttrib1fv(idx, ptr); michael@0: } michael@0: } michael@0: michael@0: void michael@0: WebGLContext::VertexAttrib2fv_base(GLuint idx, uint32_t arrayLength, michael@0: const GLfloat* ptr) michael@0: { michael@0: if (!ValidateAttribArraySetter("VertexAttrib2fv", 2, arrayLength)) michael@0: return; michael@0: michael@0: MakeContextCurrent(); michael@0: if (idx) { michael@0: gl->fVertexAttrib2fv(idx, ptr); michael@0: } else { michael@0: mVertexAttrib0Vector[0] = ptr[0]; michael@0: mVertexAttrib0Vector[1] = ptr[1]; michael@0: mVertexAttrib0Vector[2] = GLfloat(0); michael@0: mVertexAttrib0Vector[3] = GLfloat(1); michael@0: if (gl->IsGLES()) michael@0: gl->fVertexAttrib2fv(idx, ptr); michael@0: } michael@0: } michael@0: michael@0: void michael@0: WebGLContext::VertexAttrib3fv_base(GLuint idx, uint32_t arrayLength, michael@0: const GLfloat* ptr) michael@0: { michael@0: if (!ValidateAttribArraySetter("VertexAttrib3fv", 3, arrayLength)) michael@0: return; michael@0: michael@0: MakeContextCurrent(); michael@0: if (idx) { michael@0: gl->fVertexAttrib3fv(idx, ptr); michael@0: } else { michael@0: mVertexAttrib0Vector[0] = ptr[0]; michael@0: mVertexAttrib0Vector[1] = ptr[1]; michael@0: mVertexAttrib0Vector[2] = ptr[2]; michael@0: mVertexAttrib0Vector[3] = GLfloat(1); michael@0: if (gl->IsGLES()) michael@0: gl->fVertexAttrib3fv(idx, ptr); michael@0: } michael@0: } michael@0: michael@0: void michael@0: WebGLContext::VertexAttrib4fv_base(GLuint idx, uint32_t arrayLength, michael@0: const GLfloat* ptr) michael@0: { michael@0: if (!ValidateAttribArraySetter("VertexAttrib4fv", 4, arrayLength)) michael@0: return; michael@0: michael@0: MakeContextCurrent(); michael@0: if (idx) { michael@0: gl->fVertexAttrib4fv(idx, ptr); michael@0: } else { michael@0: mVertexAttrib0Vector[0] = ptr[0]; michael@0: mVertexAttrib0Vector[1] = ptr[1]; michael@0: mVertexAttrib0Vector[2] = ptr[2]; michael@0: mVertexAttrib0Vector[3] = ptr[3]; michael@0: if (gl->IsGLES()) michael@0: gl->fVertexAttrib4fv(idx, ptr); michael@0: } michael@0: } michael@0: michael@0: void michael@0: WebGLContext::EnableVertexAttribArray(GLuint index) michael@0: { michael@0: if (IsContextLost()) michael@0: return; michael@0: michael@0: if (!ValidateAttribIndex(index, "enableVertexAttribArray")) michael@0: return; michael@0: michael@0: MakeContextCurrent(); michael@0: InvalidateBufferFetching(); michael@0: michael@0: gl->fEnableVertexAttribArray(index); michael@0: MOZ_ASSERT(mBoundVertexArray->HasAttrib(index)); // should have been validated earlier michael@0: mBoundVertexArray->mAttribs[index].enabled = true; michael@0: } michael@0: michael@0: void michael@0: WebGLContext::DisableVertexAttribArray(GLuint index) michael@0: { michael@0: if (IsContextLost()) michael@0: return; michael@0: michael@0: if (!ValidateAttribIndex(index, "disableVertexAttribArray")) michael@0: return; michael@0: michael@0: MakeContextCurrent(); michael@0: InvalidateBufferFetching(); michael@0: michael@0: if (index || gl->IsGLES()) michael@0: gl->fDisableVertexAttribArray(index); michael@0: michael@0: MOZ_ASSERT(mBoundVertexArray->HasAttrib(index)); // should have been validated earlier michael@0: mBoundVertexArray->mAttribs[index].enabled = false; michael@0: } michael@0: michael@0: michael@0: JS::Value michael@0: WebGLContext::GetVertexAttrib(JSContext* cx, GLuint index, GLenum pname, michael@0: ErrorResult& rv) michael@0: { michael@0: if (IsContextLost()) michael@0: return JS::NullValue(); michael@0: michael@0: if (!ValidateAttribIndex(index, "getVertexAttrib")) michael@0: return JS::NullValue(); michael@0: michael@0: MakeContextCurrent(); michael@0: michael@0: switch (pname) { michael@0: case LOCAL_GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: michael@0: { michael@0: return WebGLObjectAsJSValue(cx, mBoundVertexArray->mAttribs[index].buf.get(), rv); michael@0: } michael@0: michael@0: case LOCAL_GL_VERTEX_ATTRIB_ARRAY_STRIDE: michael@0: { michael@0: return JS::Int32Value(mBoundVertexArray->mAttribs[index].stride); michael@0: } michael@0: michael@0: case LOCAL_GL_VERTEX_ATTRIB_ARRAY_SIZE: michael@0: { michael@0: if (!ValidateAttribIndex(index, "getVertexAttrib")) michael@0: return JS::NullValue(); michael@0: michael@0: if (!mBoundVertexArray->mAttribs[index].enabled) michael@0: return JS::Int32Value(4); michael@0: michael@0: // Don't break; fall through. michael@0: } michael@0: case LOCAL_GL_VERTEX_ATTRIB_ARRAY_TYPE: michael@0: { michael@0: GLint i = 0; michael@0: gl->fGetVertexAttribiv(index, pname, &i); michael@0: if (pname == LOCAL_GL_VERTEX_ATTRIB_ARRAY_SIZE) michael@0: return JS::Int32Value(i); michael@0: MOZ_ASSERT(pname == LOCAL_GL_VERTEX_ATTRIB_ARRAY_TYPE); michael@0: return JS::NumberValue(uint32_t(i)); michael@0: } michael@0: michael@0: case LOCAL_GL_VERTEX_ATTRIB_ARRAY_DIVISOR: michael@0: { michael@0: if (IsExtensionEnabled(WebGLExtensionID::ANGLE_instanced_arrays)) michael@0: { michael@0: return JS::Int32Value(mBoundVertexArray->mAttribs[index].divisor); michael@0: } michael@0: break; michael@0: } michael@0: michael@0: case LOCAL_GL_CURRENT_VERTEX_ATTRIB: michael@0: { michael@0: GLfloat vec[4] = {0, 0, 0, 1}; michael@0: if (index) { michael@0: gl->fGetVertexAttribfv(index, LOCAL_GL_CURRENT_VERTEX_ATTRIB, &vec[0]); michael@0: } else { michael@0: vec[0] = mVertexAttrib0Vector[0]; michael@0: vec[1] = mVertexAttrib0Vector[1]; michael@0: vec[2] = mVertexAttrib0Vector[2]; michael@0: vec[3] = mVertexAttrib0Vector[3]; michael@0: } michael@0: JSObject* obj = Float32Array::Create(cx, this, 4, vec); michael@0: if (!obj) { michael@0: rv.Throw(NS_ERROR_OUT_OF_MEMORY); michael@0: } michael@0: return JS::ObjectOrNullValue(obj); michael@0: } michael@0: michael@0: case LOCAL_GL_VERTEX_ATTRIB_ARRAY_ENABLED: michael@0: { michael@0: return JS::BooleanValue(mBoundVertexArray->mAttribs[index].enabled); michael@0: } michael@0: michael@0: case LOCAL_GL_VERTEX_ATTRIB_ARRAY_NORMALIZED: michael@0: { michael@0: return JS::BooleanValue(mBoundVertexArray->mAttribs[index].normalized); michael@0: } michael@0: michael@0: default: michael@0: break; michael@0: } michael@0: michael@0: ErrorInvalidEnumInfo("getVertexAttrib: parameter", pname); michael@0: michael@0: return JS::NullValue(); michael@0: } michael@0: michael@0: WebGLsizeiptr michael@0: WebGLContext::GetVertexAttribOffset(GLuint index, GLenum pname) michael@0: { michael@0: if (IsContextLost()) michael@0: return 0; michael@0: michael@0: if (!ValidateAttribIndex(index, "getVertexAttribOffset")) michael@0: return 0; michael@0: michael@0: if (pname != LOCAL_GL_VERTEX_ATTRIB_ARRAY_POINTER) { michael@0: ErrorInvalidEnum("getVertexAttribOffset: bad parameter"); michael@0: return 0; michael@0: } michael@0: michael@0: return mBoundVertexArray->mAttribs[index].byteOffset; michael@0: } michael@0: michael@0: void michael@0: WebGLContext::VertexAttribPointer(GLuint index, GLint size, GLenum type, michael@0: WebGLboolean normalized, GLsizei stride, michael@0: WebGLintptr byteOffset) michael@0: { michael@0: if (IsContextLost()) michael@0: return; michael@0: michael@0: if (mBoundArrayBuffer == nullptr) michael@0: return ErrorInvalidOperation("vertexAttribPointer: must have valid GL_ARRAY_BUFFER binding"); michael@0: michael@0: GLsizei requiredAlignment = 1; michael@0: switch (type) { michael@0: case LOCAL_GL_BYTE: michael@0: case LOCAL_GL_UNSIGNED_BYTE: michael@0: requiredAlignment = 1; michael@0: break; michael@0: case LOCAL_GL_SHORT: michael@0: case LOCAL_GL_UNSIGNED_SHORT: michael@0: requiredAlignment = 2; michael@0: break; michael@0: // XXX case LOCAL_GL_FIXED: michael@0: case LOCAL_GL_FLOAT: michael@0: requiredAlignment = 4; michael@0: break; michael@0: default: michael@0: return ErrorInvalidEnumInfo("vertexAttribPointer: type", type); michael@0: } michael@0: michael@0: // requiredAlignment should always be a power of two. michael@0: GLsizei requiredAlignmentMask = requiredAlignment - 1; michael@0: michael@0: if (!ValidateAttribIndex(index, "vertexAttribPointer")) { michael@0: return; michael@0: } michael@0: michael@0: if (size < 1 || size > 4) michael@0: return ErrorInvalidValue("vertexAttribPointer: invalid element size"); michael@0: michael@0: if (stride < 0 || stride > 255) // see WebGL spec section 6.6 "Vertex Attribute Data Stride" michael@0: return ErrorInvalidValue("vertexAttribPointer: negative or too large stride"); michael@0: michael@0: if (byteOffset < 0) michael@0: return ErrorInvalidValue("vertexAttribPointer: negative offset"); michael@0: michael@0: if (stride & requiredAlignmentMask) { michael@0: return ErrorInvalidOperation("vertexAttribPointer: stride doesn't satisfy the alignment " michael@0: "requirement of given type"); michael@0: } michael@0: michael@0: if (byteOffset & requiredAlignmentMask) { michael@0: return ErrorInvalidOperation("vertexAttribPointer: byteOffset doesn't satisfy the alignment " michael@0: "requirement of given type"); michael@0: michael@0: } michael@0: michael@0: InvalidateBufferFetching(); michael@0: michael@0: /* XXX make work with bufferSubData & heterogeneous types michael@0: if (type != mBoundArrayBuffer->GLType()) michael@0: return ErrorInvalidOperation("vertexAttribPointer: type must match bound VBO type: %d != %d", type, mBoundArrayBuffer->GLType()); michael@0: */ michael@0: michael@0: WebGLVertexAttribData &vd = mBoundVertexArray->mAttribs[index]; michael@0: michael@0: vd.buf = mBoundArrayBuffer; michael@0: vd.stride = stride; michael@0: vd.size = size; michael@0: vd.byteOffset = byteOffset; michael@0: vd.type = type; michael@0: vd.normalized = normalized; michael@0: michael@0: MakeContextCurrent(); michael@0: michael@0: gl->fVertexAttribPointer(index, size, type, normalized, michael@0: stride, michael@0: reinterpret_cast(byteOffset)); michael@0: } michael@0: michael@0: void michael@0: WebGLContext::VertexAttribDivisor(GLuint index, GLuint divisor) michael@0: { michael@0: if (IsContextLost()) michael@0: return; michael@0: michael@0: if (!ValidateAttribIndex(index, "vertexAttribDivisor")) { michael@0: return; michael@0: } michael@0: michael@0: WebGLVertexAttribData& vd = mBoundVertexArray->mAttribs[index]; michael@0: vd.divisor = divisor; michael@0: michael@0: InvalidateBufferFetching(); michael@0: michael@0: MakeContextCurrent(); michael@0: michael@0: gl->fVertexAttribDivisor(index, divisor); michael@0: }