fixed #16871: Material second shader texture will be lost when removeUnusedTextures is invoked. (#16884)

* fixed #16871: Material second shader texture will be lost when removeUnusedTextures is invoked.

* issue #16871: Adds test case for issue #16871.

* issue #16871: Checks whether current texture is the same as which is passed in. And more comments for release stuffs.

* Removes unused nullptr check of _value.tex.texture

CC_SAFE_RETAIN will check it.
And some indention fixes.
This commit is contained in:
James Chen 2017-02-10 14:01:26 +08:00 committed by minggo
parent 34d4c65c86
commit 27e2012cf1
5 changed files with 129 additions and 23 deletions

View File

@ -65,10 +65,20 @@ UniformValue::UniformValue(Uniform *uniform, GLProgram* glprogram)
{
}
UniformValue::UniformValue(const UniformValue& o)
{
*this = o;
}
UniformValue::~UniformValue()
{
if (_type == Type::CALLBACK_FN)
delete _value.callback;
if (_type == Type::CALLBACK_FN)
delete _value.callback;
if (_uniform->type == GL_SAMPLER_2D)
{
CC_SAFE_RELEASE(_value.tex.texture);
}
}
void UniformValue::apply()
@ -147,12 +157,12 @@ void UniformValue::apply()
void UniformValue::setCallback(const std::function<void(GLProgram*, Uniform*)> &callback)
{
// delete previously set callback
// TODO: memory will leak if the user does:
// value->setCallback();
// value->setFloat();
// delete previously set callback
// TODO: memory will leak if the user does:
// value->setCallback();
// value->setFloat();
if (_type == Type::CALLBACK_FN)
delete _value.callback;
delete _value.callback;
_value.callback = new (std::nothrow) std::function<void(GLProgram*, Uniform*)>();
*_value.callback = callback;
@ -165,8 +175,26 @@ void UniformValue::setTexture(GLuint textureId, GLuint textureUnit)
//CCASSERT(_uniform->type == GL_SAMPLER_2D, "Wrong type. expecting GL_SAMPLER_2D");
_value.tex.textureId = textureId;
_value.tex.textureUnit = textureUnit;
_value.tex.texture = nullptr;
_type = Type::VALUE;
}
void UniformValue::setTexture(Texture2D* texture, GLuint textureUnit)
{
CCASSERT(texture != nullptr, "texture is nullptr");
if (texture != _value.tex.texture)
{
CC_SAFE_RELEASE(_value.tex.texture);
CC_SAFE_RETAIN(texture);
_value.tex.texture = texture;
_value.tex.textureId = texture->getName();
_value.tex.textureUnit = textureUnit;
_type = Type::VALUE;
}
}
void UniformValue::setInt(int value)
{
CCASSERT(_uniform->type == GL_INT, "Wrong type: expecting GL_INT");
@ -218,7 +246,6 @@ void UniformValue::setVec3v(ssize_t size, const Vec3* pointer)
_value.v3f.pointer = (const float*)pointer;
_value.v3f.size = (GLsizei)size;
_type = Type::POINTER;
}
void UniformValue::setVec4(const Vec4& value)
@ -243,6 +270,20 @@ void UniformValue::setMat4(const Mat4& value)
_type = Type::VALUE;
}
UniformValue& UniformValue::operator=(const UniformValue& o)
{
_uniform = o._uniform;
_glprogram = o._glprogram;
_type = o._type;
_value = o._value;
if (_uniform->type == GL_SAMPLER_2D)
{
CC_SAFE_RETAIN(_value.tex.texture);
}
return *this;
}
//
//
// VertexAttribValue
@ -396,7 +437,13 @@ GLProgramState::~GLProgramState()
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_WINRT)
Director::getInstance()->getEventDispatcher()->removeEventListener(_backToForegroundlistener);
#endif
// _uniforms must be cleared before releasing _glprogram since
// the destructor of UniformValue will call a weak pointer
// which points to the member variable in GLProgram.
_uniforms.clear();
_attributes.clear();
CC_SAFE_RELEASE(_glprogram);
}
@ -446,7 +493,7 @@ bool GLProgramState::init(GLProgram* glprogram)
for(auto &uniform : _glprogram->_userUniforms) {
UniformValue value(&uniform.second, _glprogram);
_uniforms[uniform.second.location] = value;
_uniforms[uniform.second.location] = std::move(value);
_uniformsByName[uniform.first] = uniform.second.location;
}
@ -455,10 +502,14 @@ bool GLProgramState::init(GLProgram* glprogram)
void GLProgramState::resetGLProgram()
{
CC_SAFE_RELEASE(_glprogram);
_glprogram = nullptr;
// _uniforms must be cleared before releasing _glprogram since
// the destructor of UniformValue will call a weak pointer
// which points to the member variable in GLProgram.
_uniforms.clear();
_attributes.clear();
CC_SAFE_RELEASE(_glprogram);
_glprogram = nullptr;
// first texture is GL_TEXTURE1
_textureUnitIndex = 1;
_nodeBinding = nullptr;
@ -811,13 +862,45 @@ void GLProgramState::setUniformMat4(GLint uniformLocation, const Mat4& value)
void GLProgramState::setUniformTexture(const std::string& uniformName, Texture2D *texture)
{
CCASSERT(texture, "Invalid texture");
setUniformTexture(uniformName, texture->getName());
auto v = getUniformValue(uniformName);
if (v)
{
if (_boundTextureUnits.find(uniformName) != _boundTextureUnits.end())
{
v->setTexture(texture, _boundTextureUnits[uniformName]);
}
else
{
v->setTexture(texture, _textureUnitIndex);
_boundTextureUnits[uniformName] = _textureUnitIndex++;
}
}
else
{
CCLOG("cocos2d: warning: Uniform not found: %s", uniformName.c_str());
}
}
void GLProgramState::setUniformTexture(GLint uniformLocation, Texture2D *texture)
{
CCASSERT(texture, "Invalid texture");
setUniformTexture(uniformLocation, texture->getName());
auto v = getUniformValue(uniformLocation);
if (v)
{
if (_boundTextureUnits.find(v->_uniform->name) != _boundTextureUnits.end())
{
v->setTexture(texture, _boundTextureUnits[v->_uniform->name]);
}
else
{
v->setTexture(texture, _textureUnitIndex);
_boundTextureUnits[v->_uniform->name] = _textureUnitIndex++;
}
}
else
{
CCLOG("cocos2d: warning: Uniform at location not found: %i", uniformLocation);
}
}
void GLProgramState::setUniformTexture(const std::string& uniformName, GLuint textureId)

View File

@ -71,6 +71,8 @@ public:
*/
UniformValue(Uniform *uniform, GLProgram* glprogram);
UniformValue(const UniformValue& o);
/**Destructor.*/
~UniformValue();
/**@{
@ -101,12 +103,23 @@ public:
Set texture to uniform value.
@param textureId The texture handle.
@param textureUnit The binding texture unit to be used in shader.
@deprecated please use setTexture(Texture2D* texture, GLuint textureUnit) instead,
Passing a `textureId` may trigger texture lost issue (https://github.com/cocos2d/cocos2d-x/issues/16871).
*/
void setTexture(GLuint textureId, GLuint textureUnit);
CC_DEPRECATED_ATTRIBUTE void setTexture(GLuint textureId, GLuint textureUnit);
/**
Set texture to uniform value.
@param texture The texture.
@param textureUnit The binding texture unit to be used in shader.
*/
void setTexture(Texture2D* texture, GLuint textureUnit);
/**Apply the uniform value to openGL pipeline.*/
void apply();
UniformValue& operator=(const UniformValue& o);
protected:
enum class Type {
@ -134,8 +147,9 @@ protected:
float v4Value[4];
float matrixValue[16];
struct {
GLuint textureId;
GLuint textureId; // textureId will be deprecated since we use 'texture->getName()' to get textureId.
GLuint textureUnit;
Texture2D* texture;
} tex;
struct {
const float* pointer;
@ -317,7 +331,11 @@ public:
void setUniformMat4(const std::string& uniformName, const Mat4& value);
void setUniformCallback(const std::string& uniformName, const std::function<void(GLProgram*, Uniform*)> &callback);
void setUniformTexture(const std::string& uniformName, Texture2D *texture);
void setUniformTexture(const std::string& uniformName, GLuint textureId);
/**
* @deprecated, please use setUniformTexture(const std::string& uniformName, Texture2D *texture) instead,
* Passing a `textureId` may trigger texture lost issue (https://github.com/cocos2d/cocos2d-x/issues/16871).
*/
CC_DEPRECATED_ATTRIBUTE void setUniformTexture(const std::string& uniformName, GLuint textureId);
/**@}*/
/** @{
@ -335,7 +353,11 @@ public:
void setUniformMat4(GLint uniformLocation, const Mat4& value);
void setUniformCallback(GLint uniformLocation, const std::function<void(GLProgram*, Uniform*)> &callback);
void setUniformTexture(GLint uniformLocation, Texture2D *texture);
void setUniformTexture(GLint uniformLocation, GLuint textureId);
/**
* @deprecated, please use setUniformTexture(GLint uniformLocation, Texture2D *texture) instead,
* Passing a `textureId` may trigger texture lost issue (https://github.com/cocos2d/cocos2d-x/issues/16871).
*/
CC_DEPRECATED_ATTRIBUTE void setUniformTexture(GLint uniformLocation, GLuint textureId);
/**@}*/
/**

View File

@ -132,8 +132,8 @@ void VRGenericRenderer::render(Scene* scene, Renderer* renderer)
glGetIntegerv(GL_VIEWPORT, origViewport);
glViewport(0, 0, _texSize.width, _texSize.height);
renderDistortionMesh(_leftDistortionMesh, texture->getName());
renderDistortionMesh(_rightDistortionMesh, texture->getName());
renderDistortionMesh(_leftDistortionMesh, texture);
renderDistortionMesh(_rightDistortionMesh, texture);
glViewport(origViewport[0], origViewport[1], origViewport[2], origViewport[3]);
@ -144,14 +144,14 @@ void VRGenericRenderer::render(Scene* scene, Renderer* renderer)
CHECK_GL_ERROR_DEBUG();
}
void VRGenericRenderer::renderDistortionMesh(DistortionMesh *mesh, GLint textureID)
void VRGenericRenderer::renderDistortionMesh(DistortionMesh *mesh, Texture2D* texture)
{
glBindBuffer(GL_ARRAY_BUFFER, mesh->_arrayBufferID);
_glProgramState->setVertexAttribPointer("a_position", 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void *)(0 * sizeof(float)));
_glProgramState->setVertexAttribPointer("a_textureCoord", 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void *)(2 * sizeof(float)));
_glProgramState->setVertexAttribPointer("a_vignette", 1, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void *)(4 * sizeof(float)));
_glProgramState->setUniformTexture("u_textureSampler", textureID);
_glProgramState->setUniformTexture("u_textureSampler", texture);
_glProgramState->apply(Mat4::IDENTITY);

View File

@ -63,7 +63,7 @@ public:
protected:
void setupGLProgram();
void renderDistortionMesh(DistortionMesh *mesh, GLint textureID);
void renderDistortionMesh(DistortionMesh *mesh, Texture2D* texture);
DistortionMesh* createDistortionMesh(VREye::EyeType eyeType);
experimental::FrameBuffer* _fb;

View File

@ -786,6 +786,7 @@ void Sprite3DEffectTest::addNewSpriteWithCoords(Vec2 p)
material->setTechnique("outline_noneskinned");
sprite->setMaterial(material);
sprite->setScale(6.f);
Director::getInstance()->getTextureCache()->removeUnusedTextures();
//add to scene
addChild( sprite );