author | Dan Glastonbury <dglastonbury@mozilla.com> |
Tue, 21 Apr 2015 11:02:34 +1000 | |
changeset 241026 | ee381f0c4b9351d1b4c84aaf9b5331bb44293fa1 |
parent 241025 | 1835de92a1bd0e0c652fbd92b5deaebd7b769162 |
child 241027 | 022beda1707ce51d7ffe1e03bd0002e9a3c95bd8 |
push id | 58997 |
push user | dglastonbury@mozilla.com |
push date | Fri, 24 Apr 2015 22:45:07 +0000 |
treeherder | mozilla-inbound@ee381f0c4b93 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | jgilbert |
bugs | 1048724 |
milestone | 40.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/dom/canvas/WebGL2ContextTransformFeedback.cpp +++ b/dom/canvas/WebGL2ContextTransformFeedback.cpp @@ -200,57 +200,22 @@ WebGL2Context::TransformFeedbackVaryings GLenum bufferMode) { if (IsContextLost()) return; if (!ValidateObject("transformFeedbackVaryings: program", program)) return; - GLsizei count = varyings.Length(); - GLchar** tmpVaryings = (GLchar**) moz_xmalloc(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); + program->TransformFeedbackVaryings(varyings, bufferMode); } already_AddRefed<WebGLActiveInfo> 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<char[]> 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<WebGLActiveInfo> result = new WebGLActiveInfo(tfsize, tftype, nsDependentCString(name.get())); - return result.forget(); - */ + return program->GetTransformFeedbackVarying(index); }
--- a/dom/canvas/WebGLContextBuffers.cpp +++ b/dom/canvas/WebGLContextBuffers.cpp @@ -88,21 +88,23 @@ WebGLContext::BindBufferBase(GLenum targ return; // ValidateBufferTarget switch (target) { case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER: if (index >= mGLMaxTransformFeedbackSeparateAttribs) return ErrorInvalidValue("bindBufferBase: index should be less than " "MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS"); + break; case LOCAL_GL_UNIFORM_BUFFER: if (index >= mGLMaxUniformBufferBindings) return ErrorInvalidValue("bindBufferBase: index should be less than " "MAX_UNIFORM_BUFFER_BINDINGS"); + break; default: return ErrorInvalidEnumInfo("bindBufferBase: target", target); } if (!ValidateBufferForTarget(target, buffer, "bindBufferBase")) return; @@ -126,21 +128,24 @@ WebGLContext::BindBufferRange(GLenum tar return; // ValidateBufferTarget switch (target) { case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER: if (index >= mGLMaxTransformFeedbackSeparateAttribs) return ErrorInvalidValue("bindBufferRange: index should be less than " "MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS"); + break; case LOCAL_GL_UNIFORM_BUFFER: if (index >= mGLMaxUniformBufferBindings) return ErrorInvalidValue("bindBufferRange: index should be less than " "MAX_UNIFORM_BUFFER_BINDINGS"); + break; + default: return ErrorInvalidEnumInfo("bindBufferRange: target", target); } if (!ValidateBufferForTarget(target, buffer, "bindBufferRange")) return; WebGLContextUnchecked::BindBufferRange(target, index, buffer, offset, size); @@ -490,16 +495,17 @@ WebGLContext::GetBufferSlotByTarget(GLen WebGLRefPtr<WebGLBuffer>& WebGLContext::GetBufferSlotByTargetIndexed(GLenum target, GLuint index) { /* This function assumes that target has been validated for either WebGL1 or WebGL. */ switch (target) { case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER: MOZ_ASSERT(index < mGLMaxTransformFeedbackSeparateAttribs); return mBoundTransformFeedbackBuffers[index]; + case LOCAL_GL_UNIFORM_BUFFER: MOZ_ASSERT(index < mGLMaxUniformBufferBindings); return mBoundUniformBuffers[index]; default: MOZ_CRASH("Should not get here."); } }
--- a/dom/canvas/WebGLProgram.cpp +++ b/dom/canvas/WebGLProgram.cpp @@ -225,17 +225,17 @@ QueryProgramInfo(WebGLProgram* prog, gl: // Uniform Blocks if (gl->IsSupported(gl::GLFeature::uniform_buffer_object)) { GLuint numActiveUniformBlocks = 0; gl->fGetProgramiv(prog->mGLName, LOCAL_GL_ACTIVE_UNIFORM_BLOCKS, (GLint*)&numActiveUniformBlocks); - for (GLuint i = 0; i < numActiveAttribs; i++) { + for (GLuint i = 0; i < numActiveUniformBlocks; i++) { nsAutoCString mappedName; mappedName.SetLength(maxUniformBlockLenWithNull - 1); GLint lengthWithoutNull; gl->fGetActiveUniformBlockiv(prog->mGLName, i, LOCAL_GL_UNIFORM_BLOCK_NAME_LENGTH, &lengthWithoutNull); gl->fGetActiveUniformBlockName(prog->mGLName, i, maxUniformBlockLenWithNull, &lengthWithoutNull, mappedName.BeginWriting()); mappedName.SetLength(lengthWithoutNull); @@ -290,16 +290,17 @@ CreateProgram(gl::GLContext* gl) { gl->MakeCurrent(); return gl->fCreateProgram(); } WebGLProgram::WebGLProgram(WebGLContext* webgl) : WebGLContextBoundObject(webgl) , mGLName(CreateProgram(webgl->GL())) + , mTransformFeedbackBufferMode(LOCAL_GL_NONE) { mContext->mPrograms.insertBack(this); } void WebGLProgram::Delete() { gl::GLContext* gl = mContext->GL(); @@ -427,16 +428,17 @@ WebGLProgram::GetActiveAttrib(GLuint ind nsRefPtr<WebGLActiveInfo> ret = activeList[index]; return ret.forget(); } already_AddRefed<WebGLActiveInfo> WebGLProgram::GetActiveUniform(GLuint index) const { if (!mMostRecentLinkInfo) { + // According to the spec, this can return null. nsRefPtr<WebGLActiveInfo> ret = WebGLActiveInfo::CreateInvalid(mContext); return ret.forget(); } const auto& activeList = mMostRecentLinkInfo->activeUniforms; if (index >= activeList.size()) { mContext->ErrorInvalidValue("`index` (%i) must be less than %s (%i).", @@ -527,20 +529,22 @@ WebGLProgram::GetProgramParameter(GLenum { gl::GLContext* gl = mContext->gl; gl->MakeCurrent(); if (mContext->IsWebGL2()) { switch (pname) { case LOCAL_GL_ACTIVE_UNIFORM_BLOCKS: return JS::Int32Value(GetProgramiv(gl, mGLName, pname)); - } + + case LOCAL_GL_TRANSFORM_FEEDBACK_VARYINGS: + return JS::Int32Value(mTransformFeedbackVaryings.size()); + } } - switch (pname) { case LOCAL_GL_ATTACHED_SHADERS: case LOCAL_GL_ACTIVE_UNIFORMS: case LOCAL_GL_ACTIVE_ATTRIBUTES: return JS::Int32Value(GetProgramiv(gl, mGLName, pname)); case LOCAL_GL_DELETE_STATUS: return JS::BooleanValue(IsDeleteRequested()); @@ -814,16 +818,25 @@ WebGLProgram::LinkProgram() // This can't be done trivially, because we have to deal with mapped attrib names. for (auto itr = mBoundAttribLocs.begin(); itr != mBoundAttribLocs.end(); ++itr) { const nsCString& name = itr->first; GLuint index = itr->second; mVertShader->BindAttribLocation(mGLName, name, index); } + if (!mTransformFeedbackVaryings.empty()) { + // Bind the transform feedback varyings. + // This can't be done trivially, because we have to deal with mapped names too. + mVertShader->ApplyTransformFeedbackVaryings(mGLName, + mTransformFeedbackVaryings, + mTransformFeedbackBufferMode, + &mTempMappedVaryings); + } + if (LinkAndUpdate()) return true; // Failed link. if (mContext->ShouldGenerateWarnings()) { // report shader/program infoLogs as warnings. // note that shader compilation errors can be deferred to linkProgram, // which is why we can't do anything in compileShader. In practice we could @@ -891,16 +904,21 @@ WebGLProgram::LinkAndUpdate() gl->fGetProgramiv(mGLName, LOCAL_GL_INFO_LOG_LENGTH, (GLint*)&logLenWithNull); if (logLenWithNull > 1) { mLinkLog.SetLength(logLenWithNull - 1); gl->fGetProgramInfoLog(mGLName, logLenWithNull, nullptr, mLinkLog.BeginWriting()); } else { mLinkLog.SetLength(0); } + // Post link, temporary mapped varying names for transform feedback can be discarded. + // The memory can only be deleted after log is queried or the link status will fail. + std::vector<std::string> empty; + empty.swap(mTempMappedVaryings); + GLint ok = 0; gl->fGetProgramiv(mGLName, LOCAL_GL_LINK_STATUS, &ok); if (!ok) return false; mMostRecentLinkInfo = QueryProgramInfo(this, gl); MOZ_ASSERT(mMostRecentLinkInfo); @@ -929,16 +947,81 @@ WebGLProgram::FindUniformByMappedName(co return true; if (mFragShader->FindUniformByMappedName(mappedName, out_userName, out_isArray)) return true; return false; } +void +WebGLProgram::TransformFeedbackVaryings(const dom::Sequence<nsString>& varyings, + GLenum bufferMode) +{ + if (bufferMode != LOCAL_GL_INTERLEAVED_ATTRIBS && + bufferMode != LOCAL_GL_SEPARATE_ATTRIBS) + { + mContext->ErrorInvalidEnum("transformFeedbackVaryings: `bufferMode` %s is " + "invalid. Must be one of gl.INTERLEAVED_ATTRIBS or " + "gl.SEPARATE_ATTRIBS.", + mContext->EnumName(bufferMode)); + return; + } + + size_t varyingsCount = varyings.Length(); + if (bufferMode == LOCAL_GL_SEPARATE_ATTRIBS && + varyingsCount >= mContext->mGLMaxTransformFeedbackSeparateAttribs) + { + mContext->ErrorInvalidValue("transformFeedbackVaryings: Number of `varyings` exc" + "eeds gl.MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS."); + return; + } + + std::vector<nsCString> asciiVaryings; + for (size_t i = 0; i < varyingsCount; i++) { + if (!ValidateGLSLVariableName(varyings[i], mContext, "transformFeedbackVaryings")) + return; + + NS_LossyConvertUTF16toASCII asciiName(varyings[i]); + asciiVaryings.push_back(asciiName); + } + + // All validated. Translate the strings and store them until + // program linking. + mTransformFeedbackBufferMode = bufferMode; + mTransformFeedbackVaryings.swap(asciiVaryings); +} + +already_AddRefed<WebGLActiveInfo> +WebGLProgram::GetTransformFeedbackVarying(GLuint index) +{ + // No docs in the WebGL 2 spec for this function. Taking the language for + // getActiveAttrib, which states that the function returns null on any error. + if (!IsLinked()) { + mContext->ErrorInvalidOperation("getTransformFeedbackVarying: `program` must be " + "linked."); + return nullptr; + } + + if (index >= mTransformFeedbackVaryings.size()) { + mContext->ErrorInvalidValue("getTransformFeedbackVarying: `index` is greater or " + "equal to TRANSFORM_FEEDBACK_VARYINGS."); + return nullptr; + } + + const nsCString& varyingUserName = mTransformFeedbackVaryings[index]; + + WebGLActiveInfo* info; + LinkInfo()->FindAttrib(varyingUserName, (const WebGLActiveInfo**) &info); + MOZ_ASSERT(info); + + nsRefPtr<WebGLActiveInfo> ret(info); + return ret.forget(); +} + bool WebGLProgram::FindUniformBlockByMappedName(const nsACString& mappedName, nsCString* const out_userName, bool* const out_isArray) const { if (mVertShader->FindUniformBlockByMappedName(mappedName, out_userName, out_isArray)) return true;
--- a/dom/canvas/WebGLProgram.h +++ b/dom/canvas/WebGLProgram.h @@ -168,16 +168,20 @@ public: nsDependentCString* const out_userName) const; bool FindUniformByMappedName(const nsACString& mappedName, nsCString* const out_userName, bool* const out_isArray) const; bool FindUniformBlockByMappedName(const nsACString& mappedName, nsCString* const out_userName, bool* const out_isArray) const; + void TransformFeedbackVaryings(const dom::Sequence<nsString>& varyings, + GLenum bufferMode); + already_AddRefed<WebGLActiveInfo> GetTransformFeedbackVarying(GLuint index); + bool IsLinked() const { return mMostRecentLinkInfo; } const webgl::LinkedProgramInfo* LinkInfo() const { return mMostRecentLinkInfo.get(); } WebGLContext* GetParentObject() const { return Context(); @@ -194,15 +198,20 @@ private: public: const GLuint mGLName; private: WebGLRefPtr<WebGLShader> mVertShader; WebGLRefPtr<WebGLShader> mFragShader; std::map<nsCString, GLuint> mBoundAttribLocs; + std::vector<nsCString> mTransformFeedbackVaryings; + GLenum mTransformFeedbackBufferMode; nsCString mLinkLog; RefPtr<const webgl::LinkedProgramInfo> mMostRecentLinkInfo; + // Storage for transform feedback varyings before link. + // (Work around for bug seen on nVidia drivers.) + std::vector<std::string> mTempMappedVaryings; }; } // namespace mozilla #endif // WEBGL_PROGRAM_H_
--- a/dom/canvas/WebGLShader.cpp +++ b/dom/canvas/WebGLShader.cpp @@ -349,16 +349,54 @@ bool WebGLShader::FindUniformBlockByMappedName(const nsACString& mappedName, nsCString* const out_userName, bool* const out_isArray) const { // TODO: Extract block information from shader validator. return false; } +void +WebGLShader::ApplyTransformFeedbackVaryings(GLuint prog, + const std::vector<nsCString>& varyings, + GLenum bufferMode, + std::vector<std::string>* out_mappedVaryings) const +{ + MOZ_ASSERT(mType == LOCAL_GL_VERTEX_SHADER); + MOZ_ASSERT(!varyings.empty()); + MOZ_ASSERT(out_mappedVaryings); + + const size_t varyingsCount = varyings.size(); + std::vector<std::string> mappedVaryings; + + for (size_t i = 0; i < varyingsCount; i++) { + const nsCString& userName = varyings[i]; + std::string userNameStr(userName.BeginReading()); + + const std::string* mappedNameStr = &userNameStr; + // TODO: Are vertex->fragment shader varyings listed under attribs? + if (mValidator) + mValidator->FindAttribMappedNameByUserName(userNameStr, &mappedNameStr); + + mappedVaryings.push_back(*mappedNameStr); + } + + // Temporary, tight packed array of string pointers into mappedVaryings. + std::vector<const GLchar*> strings; + strings.resize(varyingsCount); + for (size_t i = 0; i < varyingsCount; i++) { + strings[i] = mappedVaryings[i].c_str(); + } + + mContext->MakeContextCurrent(); + mContext->gl->fTransformFeedbackVaryings(prog, varyingsCount, &strings[0], bufferMode); + + out_mappedVaryings->swap(mappedVaryings); +} + //////////////////////////////////////////////////////////////////////////////// // Boilerplate JSObject* WebGLShader::WrapObject(JSContext* js, JS::Handle<JSObject*> aGivenProto) { return dom::WebGLShaderBinding::Wrap(js, this, aGivenProto); }
--- a/dom/canvas/WebGLShader.h +++ b/dom/canvas/WebGLShader.h @@ -54,16 +54,21 @@ public: bool FindUniformBlockByMappedName(const nsACString& mappedName, nsCString* const out_userName, bool* const out_isArray) const; bool IsCompiled() const { return mTranslationSuccessful && mCompilationSuccessful; } + void ApplyTransformFeedbackVaryings(GLuint prog, + const std::vector<nsCString>& varyings, + GLenum bufferMode, + std::vector<std::string>* out_mappedVaryings) const; + // Other funcs size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; void Delete(); WebGLContext* GetParentObject() const { return Context(); } virtual JSObject* WrapObject(JSContext* js, JS::Handle<JSObject*> aGivenProto) override;