/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "WebGL2Context.h" #include "WebGLActiveInfo.h" #include "WebGLProgram.h" #include "WebGLTransformFeedback.h" #include "GLContext.h" using namespace mozilla; using namespace mozilla::dom; // ------------------------------------------------------------------------- // Transform Feedback already_AddRefed WebGL2Context::CreateTransformFeedback() { if (IsContextLost()) return nullptr; GLuint tf = 0; MakeContextCurrent(); gl->fGenTransformFeedbacks(1, &tf); nsRefPtr globj = new WebGLTransformFeedback(this, tf); return globj.forget(); } void WebGL2Context::DeleteTransformFeedback(WebGLTransformFeedback* tf) { if (IsContextLost()) return; if (!ValidateObjectAllowDeletedOrNull("deleteTransformFeedback", tf)) return; if (!tf || tf->IsDeleted()) return; if (mBoundTransformFeedback == tf) BindTransformFeedback(LOCAL_GL_TRANSFORM_FEEDBACK, tf); tf->RequestDelete(); } bool WebGL2Context::IsTransformFeedback(WebGLTransformFeedback* tf) { if (IsContextLost()) return false; if (!ValidateObjectAllowDeleted("isTransformFeedback", tf)) return false; if (tf->IsDeleted()) return false; MakeContextCurrent(); return gl->fIsTransformFeedback(tf->GLName()); } void WebGL2Context::BindTransformFeedback(GLenum target, WebGLTransformFeedback* tf) { if (IsContextLost()) return; if (!ValidateObjectAllowDeletedOrNull("bindTransformFeedback", tf)) return; if (target != LOCAL_GL_TRANSFORM_FEEDBACK) return ErrorInvalidEnum("bindTransformFeedback: target must be TRANSFORM_FEEDBACK"); WebGLRefPtr currentTF = mBoundTransformFeedback; if (currentTF && currentTF->mIsActive && !currentTF->mIsPaused) { return ErrorInvalidOperation("bindTransformFeedback: Currently bound transform " "feedback is active and not paused"); } if (tf && tf->IsDeleted()) return ErrorInvalidOperation("bindTransformFeedback: Attempt to bind deleted id"); if (tf) tf->BindTo(LOCAL_GL_TRANSFORM_FEEDBACK); MakeContextCurrent(); gl->fBindTransformFeedback(target, tf ? tf->GLName() : 0); if (tf) mBoundTransformFeedback = tf; else mBoundTransformFeedback = mDefaultTransformFeedback; } 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; } 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; } 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; } 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; } void WebGL2Context::TransformFeedbackVaryings(WebGLProgram* program, const dom::Sequence& varyings, GLenum bufferMode) { if (IsContextLost()) return; if (!ValidateObject("transformFeedbackVaryings: program", program)) return; GLsizei count = varyings.Length(); GLchar** tmpVaryings = (GLchar**) nsMemory::Alloc(count * sizeof(GLchar*)); for (GLsizei n = 0; n < count; n++) { tmpVaryings[n] = (GLchar*) ToNewCString(varyings[n]); } GLuint progname = program->mGLName; MakeContextCurrent(); gl->fTransformFeedbackVaryings(progname, count, tmpVaryings, bufferMode); NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, tmpVaryings); } already_AddRefed WebGL2Context::GetTransformFeedbackVarying(WebGLProgram* program, GLuint index) { if (IsContextLost()) return nullptr; if (!ValidateObject("getTransformFeedbackVarying: program", program)) return nullptr; MakeContextCurrent(); GLint len = 0; GLuint progname = program->mGLName; gl->fGetProgramiv(progname, LOCAL_GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH, &len); if (!len) return nullptr; UniquePtr name(new char[len]); GLint tfsize = 0; GLuint tftype = 0; gl->fGetTransformFeedbackVarying(progname, index, len, &len, &tfsize, &tftype, name.get()); if (len == 0 || tfsize == 0 || tftype == 0) return nullptr; MOZ_CRASH("todo"); /* // Reverse lookup of name nsCString reverseMappedName; prog->ReverveMapIdentifier(nsDependentCString(name), &reverseMappedName); nsRefPtr result = new WebGLActiveInfo(tfsize, tftype, nsDependentCString(name.get())); return result.forget(); */ }