Bug 1048724 - Sort out Transform Feedback Varyings. r=jgilbert

This commit is contained in:
Dan Glastonbury 2015-04-21 11:02:34 +10:00
parent 7a67faf4c4
commit 63ce88f24d
6 changed files with 146 additions and 40 deletions

View File

@ -205,18 +205,7 @@ WebGL2Context::TransformFeedbackVaryings(WebGLProgram* program,
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>
@ -228,29 +217,5 @@ WebGL2Context::GetTransformFeedbackVarying(WebGLProgram* program, GLuint index)
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);
}

View File

@ -93,11 +93,13 @@ WebGLContext::BindBufferBase(GLenum target, GLuint index, WebGLBuffer* 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);
@ -131,11 +133,14 @@ WebGLContext::BindBufferRange(GLenum target, GLuint index, WebGLBuffer* 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);
}
@ -495,6 +500,7 @@ WebGLContext::GetBufferSlotByTargetIndexed(GLenum target, GLuint index)
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];

View File

@ -230,7 +230,7 @@ QueryProgramInfo(WebGLProgram* prog, gl::GLContext* gl)
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);
@ -295,6 +295,7 @@ CreateProgram(gl::GLContext* gl)
WebGLProgram::WebGLProgram(WebGLContext* webgl)
: WebGLContextBoundObject(webgl)
, mGLName(CreateProgram(webgl->GL()))
, mTransformFeedbackBufferMode(LOCAL_GL_NONE)
{
mContext->mPrograms.insertBack(this);
}
@ -432,6 +433,7 @@ 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();
}
@ -532,9 +534,11 @@ WebGLProgram::GetProgramParameter(GLenum pname) const
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:
@ -819,6 +823,15 @@ WebGLProgram::LinkProgram()
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;
@ -896,6 +909,11 @@ WebGLProgram::LinkAndUpdate()
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)
@ -934,6 +952,71 @@ WebGLProgram::FindUniformByMappedName(const nsACString& mappedName,
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,

View File

@ -173,6 +173,10 @@ public:
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 {
@ -199,8 +203,13 @@ 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

View File

@ -354,6 +354,44 @@ WebGLShader::FindUniformBlockByMappedName(const nsACString& mappedName,
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

View File

@ -59,6 +59,11 @@ public:
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();