diff --git a/cocos/2d/CCAtlasNode.cpp b/cocos/2d/CCAtlasNode.cpp index 91183550d3..3b4d145f85 100644 --- a/cocos/2d/CCAtlasNode.cpp +++ b/cocos/2d/CCAtlasNode.cpp @@ -118,7 +118,8 @@ bool AtlasNode::initWithTexture(Texture2D* texture, int tileWidth, int tileHeigh } _textureAtlas->initWithTexture(texture, itemsToRender); - + + updateProgramStateTexture(texture); this->updateBlendFunc(); this->updateOpacityModifyRGB(); @@ -157,8 +158,7 @@ void AtlasNode::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags) return; auto programState = _quadCommand.getPipelineDescriptor().programState; - programState->setTexture(_textureLocation, 0, _textureAtlas->getTexture()->getBackendTexture()); - + const auto& projectionMat = Director::getInstance()->getMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION); programState->setUniform(_mvpMatrixLocation, projectionMat.m, sizeof(projectionMat.m)); @@ -251,6 +251,8 @@ void AtlasNode::updateBlendFunc() void AtlasNode::setTexture(Texture2D *texture) { _textureAtlas->setTexture(texture); + updateProgramStateTexture(texture); + this->updateBlendFunc(); this->updateOpacityModifyRGB(); } diff --git a/cocos/2d/CCAtlasNode.h b/cocos/2d/CCAtlasNode.h index 7fe280f315..3cda55abe4 100644 --- a/cocos/2d/CCAtlasNode.h +++ b/cocos/2d/CCAtlasNode.h @@ -143,7 +143,6 @@ protected: QuadCommand _quadCommand; backend::UniformLocation _textureLocation; backend::UniformLocation _mvpMatrixLocation; - backend::ProgramState* _programState = nullptr; private: CC_DISALLOW_COPY_AND_ASSIGN(AtlasNode); diff --git a/cocos/2d/CCDrawNode.h b/cocos/2d/CCDrawNode.h index 9cb9e2af00..88f07f0e12 100644 --- a/cocos/2d/CCDrawNode.h +++ b/cocos/2d/CCDrawNode.h @@ -336,7 +336,6 @@ protected: BlendFunc _blendFunc; - backend::ProgramState* _programState = nullptr; backend::ProgramState* _programStatePoint = nullptr; backend::ProgramState* _programStateLine = nullptr; diff --git a/cocos/2d/CCFastTMXLayer.h b/cocos/2d/CCFastTMXLayer.h index f50bf7608b..e3071c6706 100644 --- a/cocos/2d/CCFastTMXLayer.h +++ b/cocos/2d/CCFastTMXLayer.h @@ -354,7 +354,6 @@ protected: backend::UniformLocation _mvpMatrixLocaiton; backend::UniformLocation _textureLocation; backend::UniformLocation _alphaValueLocation; - backend::ProgramState* _programState = nullptr; }; // end of tilemap_parallax_nodes group diff --git a/cocos/2d/CCFontAtlas.cpp b/cocos/2d/CCFontAtlas.cpp index 5818b2c204..37a8be8b6d 100644 --- a/cocos/2d/CCFontAtlas.cpp +++ b/cocos/2d/CCFontAtlas.cpp @@ -485,12 +485,12 @@ void FontAtlas::updateTextureContent(backend::PixelFormat format, int startY) _currentPageDataRGBA[i*4] = data[i*2]; _currentPageDataRGBA[i*4+3] = data[i*2+1]; } - _atlasTextures[_currentPage]->updateWithData(_currentPageDataRGBA, 0, startY, CacheTextureWidth, (int)_currentPageOrigY - startY + _currLineHeight); + _atlasTextures[_currentPage]->updateWithSubData(_currentPageDataRGBA, 0, startY, CacheTextureWidth, (int)_currentPageOrigY - startY + _currLineHeight); } else { data = _currentPageData + CacheTextureWidth * (int)startY; - _atlasTextures[_currentPage]->updateWithData(data, 0, startY, CacheTextureWidth, (int)_currentPageOrigY - startY + _currLineHeight); + _atlasTextures[_currentPage]->updateWithSubData(data, 0, startY, CacheTextureWidth, (int)_currentPageOrigY - startY + _currLineHeight); } } diff --git a/cocos/2d/CCLabel.cpp b/cocos/2d/CCLabel.cpp index b06c151702..b7390f7f23 100644 --- a/cocos/2d/CCLabel.cpp +++ b/cocos/2d/CCLabel.cpp @@ -48,6 +48,7 @@ #include "2d/CCFontFNT.h" #include "renderer/ccShaders.h" #include "renderer/backend/ProgramState.h" +#include "renderer/backend/ProgramStateRegistry.h" NS_CC_BEGIN @@ -644,9 +645,9 @@ void Label::updateShaderProgram() if (_currentLabelType == LabelType::BMFONT || _currentLabelType == LabelType::CHARMAP) { auto texture = _getTexture(this); - if(texture && texture->getAlphaTextureName()) + if(texture) { - programType = backend::ProgramType::ETC1; + programType = backend::ProgramStateRegistry::getInstance()->getProgramType(programType, texture->getBackendTexture()); } } else @@ -665,9 +666,9 @@ void Label::updateShaderProgram() else { auto texture = _getTexture(this); - if(texture && texture->getAlphaTextureName()) + if(texture) { - programType = backend::ProgramType::ETC1; + programType = backend::ProgramStateRegistry::getInstance()->getProgramType(programType, texture->getBackendTexture()); } } break; @@ -728,7 +729,6 @@ void Label::updateUniformLocations() { _mvpMatrixLocation = _programState->getUniformLocation(backend::Uniform::MVP_MATRIX); _textureLocation = _programState->getUniformLocation(backend::Uniform::TEXTURE); - _alphaTextureLocation = _programState->getUniformLocation(backend::Uniform::TEXTURE1); _textColorLocation = _programState->getUniformLocation(backend::Uniform::TEXT_COLOR); _effectColorLocation = _programState->getUniformLocation(backend::Uniform::EFFECT_COLOR); _effectTypeLocation = _programState->getUniformLocation(backend::Uniform::EFFECT_TYPE); @@ -1756,12 +1756,7 @@ void Label::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags) auto texture = textureAtlas->getTexture(); auto& pipelineQuad = _quadCommand.getPipelineDescriptor(); pipelineQuad.programState->setUniform(_mvpMatrixLocation, matrixProjection.m, sizeof(matrixProjection.m)); - pipelineQuad.programState->setTexture(_textureLocation, 0, texture->getBackendTexture()); - auto alphaTexture = textureAtlas->getTexture()->getAlphaTexture(); - if(alphaTexture && alphaTexture->getBackendTexture()) - { - pipelineQuad.programState->setTexture(_alphaTextureLocation, 1, alphaTexture->getBackendTexture()); - } + pipelineQuad.programState->setTexture(texture->getBackendTexture()); _quadCommand.init(_globalZOrder, texture, _blendFunc, textureAtlas->getQuads(), textureAtlas->getTotalQuads(), transform, flags); renderer->addCommand(&_quadCommand); } @@ -1796,12 +1791,7 @@ void Label::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags) auto *programState = command->getPipelineDescriptor().programState; Vec4 textColor(_textColorF.r, _textColorF.g, _textColorF.b, _textColorF.a); programState->setUniform(_textColorLocation, &textColor, sizeof(Vec4)); - programState->setTexture(_textureLocation, 0, textureAtlas->getTexture()->getBackendTexture()); - auto alphaTexture = textureAtlas->getTexture()->getAlphaTexture(); - if (alphaTexture && alphaTexture->getBackendTexture()) - { - programState->setTexture(_alphaTextureLocation, 1, alphaTexture->getBackendTexture()); - } + programState->setTexture(textureAtlas->getTexture()->getBackendTexture()); } batch.textCommand.getPipelineDescriptor().programState->setUniform(_mvpMatrixLocation, matrixMVP.m, sizeof(matrixMVP.m)); batch.outLineCommand.getPipelineDescriptor().programState->setUniform(_mvpMatrixLocation, matrixMVP.m, sizeof(matrixMVP.m)); diff --git a/cocos/2d/CCLabel.h b/cocos/2d/CCLabel.h index 5f59a3325d..5dab114f3e 100644 --- a/cocos/2d/CCLabel.h +++ b/cocos/2d/CCLabel.h @@ -811,12 +811,9 @@ protected: backend::UniformLocation _mvpMatrixLocation; backend::UniformLocation _textureLocation; - backend::UniformLocation _alphaTextureLocation; backend::UniformLocation _textColorLocation; backend::UniformLocation _effectColorLocation; backend::UniformLocation _effectTypeLocation; - - backend::ProgramState* _programState = nullptr; private: CC_DISALLOW_COPY_AND_ASSIGN(Label); diff --git a/cocos/2d/CCLayer.h b/cocos/2d/CCLayer.h index 38e62b61a8..51aeaa7dc6 100644 --- a/cocos/2d/CCLayer.h +++ b/cocos/2d/CCLayer.h @@ -278,7 +278,6 @@ protected: V3F_C4F _vertexData[4]; backend::UniformLocation _mvpMatrixLocation; - backend::ProgramState* _programState = nullptr; private: CC_DISALLOW_COPY_AND_ASSIGN(LayerColor); diff --git a/cocos/2d/CCMotionStreak.cpp b/cocos/2d/CCMotionStreak.cpp index fa7f129e42..d324944aa9 100644 --- a/cocos/2d/CCMotionStreak.cpp +++ b/cocos/2d/CCMotionStreak.cpp @@ -40,32 +40,6 @@ MotionStreak::MotionStreak() { _customCommand.setDrawType(CustomCommand::DrawType::ARRAY); _customCommand.setPrimitiveType(CustomCommand::PrimitiveType::TRIANGLE_STRIP); - - auto& pipelineDescriptor = _customCommand.getPipelineDescriptor(); - auto* program = backend::Program::getBuiltinProgram(backend::ProgramType::POSITION_TEXTURE_COLOR); - _programState = new (std::nothrow) backend::ProgramState(program); - pipelineDescriptor.programState = _programState; - _mvpMatrixLocaiton = pipelineDescriptor.programState->getUniformLocation("u_MVPMatrix"); - _textureLocation = pipelineDescriptor.programState->getUniformLocation("u_texture"); - - auto vertexLayout = _programState->getVertexLayout(); - const auto& attributeInfo = _programState->getProgram()->getActiveAttributes(); - auto iter = attributeInfo.find("a_position"); - if(iter != attributeInfo.end()) - { - vertexLayout->setAttribute("a_position", iter->second.location, backend::VertexFormat::FLOAT2, 0, false); - } - iter = attributeInfo.find("a_texCoord"); - if(iter != attributeInfo.end()) - { - vertexLayout->setAttribute("a_texCoord", iter->second.location, backend::VertexFormat::FLOAT2, 2 * sizeof(float), false); - } - iter = attributeInfo.find("a_color"); - if(iter != attributeInfo.end()) - { - vertexLayout->setAttribute("a_color", iter->second.location, backend::VertexFormat::UBYTE4, 4 * sizeof(float), true); - } - vertexLayout->setLayout(4 * sizeof(float) + 4 * sizeof(uint8_t)); } MotionStreak::~MotionStreak() @@ -236,9 +210,49 @@ void MotionStreak::setTexture(Texture2D *texture) CC_SAFE_RETAIN(texture); CC_SAFE_RELEASE(_texture); _texture = texture; + + setProgramStateWithRegistry(backend::ProgramType::POSITION_TEXTURE_COLOR, _texture); + + if (_texture) + _programState->setTexture(_texture->getBackendTexture()); } } +void MotionStreak::setProgramState(backend::ProgramState* programState) +{ + CCASSERT(programState, "argument should not be nullptr"); + auto& pipelineDescriptor = _customCommand.getPipelineDescriptor(); + if (_programState != programState) + { + CC_SAFE_RELEASE(_programState); + _programState = programState; + CC_SAFE_RETAIN(programState); + } + pipelineDescriptor.programState = _programState; + + _mvpMatrixLocaiton = _programState->getUniformLocation("u_MVPMatrix"); + _textureLocation = _programState->getUniformLocation("u_texture"); + + auto vertexLayout = _programState->getVertexLayout(); + const auto& attributeInfo = _programState->getProgram()->getActiveAttributes(); + auto iter = attributeInfo.find("a_position"); + if (iter != attributeInfo.end()) + { + vertexLayout->setAttribute("a_position", iter->second.location, backend::VertexFormat::FLOAT2, 0, false); + } + iter = attributeInfo.find("a_texCoord"); + if (iter != attributeInfo.end()) + { + vertexLayout->setAttribute("a_texCoord", iter->second.location, backend::VertexFormat::FLOAT2, 2 * sizeof(float), false); + } + iter = attributeInfo.find("a_color"); + if (iter != attributeInfo.end()) + { + vertexLayout->setAttribute("a_color", iter->second.location, backend::VertexFormat::UBYTE4, 4 * sizeof(float), true); + } + vertexLayout->setLayout(4 * sizeof(float) + 4 * sizeof(uint8_t)); +} + void MotionStreak::setBlendFunc(const BlendFunc &blendFunc) { _blendFunc = blendFunc; @@ -398,7 +412,7 @@ void MotionStreak::draw(Renderer *renderer, const Mat4 &transform, uint32_t flag renderer->addCommand(&_customCommand); auto programState = _customCommand.getPipelineDescriptor().programState; - programState->setTexture(_textureLocation, 0, _texture->getBackendTexture()); + // programState->setTexture(_textureLocation, 0, _texture->getBackendTexture()); const auto& projectionMat = Director::getInstance()->getMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION); Mat4 finalMat = projectionMat * transform; diff --git a/cocos/2d/CCMotionStreak.h b/cocos/2d/CCMotionStreak.h index 76d8b6c576..65107f3f46 100644 --- a/cocos/2d/CCMotionStreak.h +++ b/cocos/2d/CCMotionStreak.h @@ -147,6 +147,8 @@ public: _startingPositionInitialized = bStartingPositionInitialized; } + void setProgramState(backend::ProgramState* programState) override; + CC_CONSTRUCTOR_ACCESS: MotionStreak(); virtual ~MotionStreak(); @@ -187,7 +189,6 @@ protected: backend::UniformLocation _mvpMatrixLocaiton; backend::UniformLocation _textureLocation; - backend::ProgramState* _programState = nullptr; private: CC_DISALLOW_COPY_AND_ASSIGN(MotionStreak); diff --git a/cocos/2d/CCNode.cpp b/cocos/2d/CCNode.cpp index f203c62dc6..5c3e68fa12 100644 --- a/cocos/2d/CCNode.cpp +++ b/cocos/2d/CCNode.cpp @@ -43,6 +43,7 @@ THE SOFTWARE. #include "2d/CCComponent.h" #include "renderer/CCMaterial.h" #include "math/TransformUtils.h" +#include "renderer/backend/ProgramStateRegistry.h" #if CC_NODE_RENDER_SUBPIXEL @@ -2181,6 +2182,20 @@ int Node::getAttachedNodeCount() return __attachedNodeCount; } +void Node::setProgramStateWithRegistry(backend::ProgramType programType, Texture2D* texture) +{ + auto n = texture ? texture->getBackendTexture()->getCount() : 1; + setProgramState(backend::ProgramStateRegistry::getInstance()->getProgramState(programType, n)); +} + +void Node::updateProgramStateTexture(Texture2D* texture) +{ + if (texture == nullptr || texture->getBackendTexture() == nullptr || _programState == nullptr) + return; + + _programState->setTexture(texture->getBackendTexture()); +} + void Node::setProgramState(backend::ProgramState* programState) { if (_programState != programState) diff --git a/cocos/2d/CCNode.h b/cocos/2d/CCNode.h index bbab0deef6..5ed9686408 100644 --- a/cocos/2d/CCNode.h +++ b/cocos/2d/CCNode.h @@ -1768,6 +1768,10 @@ public: virtual void setCameraMask(unsigned short mask, bool applyChildren = true); virtual void setProgramState(backend::ProgramState* programState); + + void setProgramStateWithRegistry(backend::ProgramType programType, Texture2D* texture); + void updateProgramStateTexture(Texture2D* texture); + virtual backend::ProgramState* getProgramState() const; CC_CONSTRUCTOR_ACCESS: diff --git a/cocos/2d/CCParticleBatchNode.cpp b/cocos/2d/CCParticleBatchNode.cpp index e6ab3b9ea0..4ce7dd3d55 100644 --- a/cocos/2d/CCParticleBatchNode.cpp +++ b/cocos/2d/CCParticleBatchNode.cpp @@ -441,7 +441,7 @@ void ParticleBatchNode::draw(Renderer* renderer, const Mat4 & transform, uint32_ Mat4 finalMat = projectionMat * transform; auto programState = _customCommand.getPipelineDescriptor().programState; programState->setUniform(_mvpMatrixLocaiton, finalMat.m, sizeof(finalMat.m)); - programState->setTexture(_textureLocation, 0, _textureAtlas->getTexture()->getBackendTexture()); + // programState->setTexture(_textureLocation, 0, _textureAtlas->getTexture()->getBackendTexture()); if (_textureAtlas->isDirty()) { @@ -531,11 +531,14 @@ void ParticleBatchNode::updateBlendFunc() void ParticleBatchNode::setTexture(Texture2D* texture) { _textureAtlas->setTexture(texture); - - // If the new texture has No premultiplied alpha, AND the blendFunc hasn't been changed, then update it - if( texture && ! texture->hasPremultipliedAlpha() && ( _blendFunc.src == CC_BLEND_SRC && _blendFunc.dst == CC_BLEND_DST ) ) - { - _blendFunc = BlendFunc::ALPHA_NON_PREMULTIPLIED; + if (texture) { + auto programState = _customCommand.getPipelineDescriptor().programState; + programState->setTexture(_textureAtlas->getTexture()->getBackendTexture()); + // If the new texture has No premultiplied alpha, AND the blendFunc hasn't been changed, then update it + if (!texture->hasPremultipliedAlpha() && (_blendFunc.src == CC_BLEND_SRC && _blendFunc.dst == CC_BLEND_DST)) + { + _blendFunc = BlendFunc::ALPHA_NON_PREMULTIPLIED; + } } } diff --git a/cocos/2d/CCParticleBatchNode.h b/cocos/2d/CCParticleBatchNode.h index b81b4e609d..9a24fffc11 100644 --- a/cocos/2d/CCParticleBatchNode.h +++ b/cocos/2d/CCParticleBatchNode.h @@ -180,7 +180,6 @@ private: backend::UniformLocation _mvpMatrixLocaiton; backend::UniformLocation _textureLocation; - backend::ProgramState* _programState = nullptr; }; // end of _2d group diff --git a/cocos/2d/CCParticleSystemQuad.cpp b/cocos/2d/CCParticleSystemQuad.cpp index f69c9048d2..9660bc5de0 100644 --- a/cocos/2d/CCParticleSystemQuad.cpp +++ b/cocos/2d/CCParticleSystemQuad.cpp @@ -230,6 +230,9 @@ void ParticleSystemQuad::setTextureWithRect(Texture2D *texture, const Rect& rect if( !_texture || texture->getBackendTexture() != _texture->getBackendTexture() ) { ParticleSystem::setTexture(texture); + + auto programState = _quadCommand.getPipelineDescriptor().programState; + programState->setTexture(_texture->getBackendTexture()); } this->initTexCoordsWithRect(rect); @@ -446,7 +449,7 @@ void ParticleSystemQuad::draw(Renderer *renderer, const Mat4 &transform, uint32_ if(_particleCount > 0) { auto programState = _quadCommand.getPipelineDescriptor().programState; - programState->setTexture(_textureLocation, 0, _texture->getBackendTexture()); + // programState->setTexture(_textureLocation, 0, _texture->getBackendTexture()); cocos2d::Mat4 projectionMat = Director::getInstance()->getMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION); programState->setUniform(_mvpMatrixLocaiton, projectionMat.m, sizeof(projectionMat.m)); diff --git a/cocos/2d/CCParticleSystemQuad.h b/cocos/2d/CCParticleSystemQuad.h index 29ff4bd0c8..71e195f2a4 100644 --- a/cocos/2d/CCParticleSystemQuad.h +++ b/cocos/2d/CCParticleSystemQuad.h @@ -176,7 +176,6 @@ protected: backend::UniformLocation _mvpMatrixLocaiton; backend::UniformLocation _textureLocation; - backend::ProgramState* _programState = nullptr; private: CC_DISALLOW_COPY_AND_ASSIGN(ParticleSystemQuad); diff --git a/cocos/2d/CCProgressTimer.h b/cocos/2d/CCProgressTimer.h index 83b9de0b73..54c23c4adb 100644 --- a/cocos/2d/CCProgressTimer.h +++ b/cocos/2d/CCProgressTimer.h @@ -191,7 +191,6 @@ protected: CustomCommand _customCommand; CustomCommand _customCommand2; - backend::ProgramState* _programState = nullptr; backend::ProgramState* _programState2 = nullptr; backend::UniformLocation _locMVP1; diff --git a/cocos/2d/CCSprite.cpp b/cocos/2d/CCSprite.cpp index eb20451354..17ab9163fb 100644 --- a/cocos/2d/CCSprite.cpp +++ b/cocos/2d/CCSprite.cpp @@ -384,14 +384,15 @@ void Sprite::updateShaders(const char* vert, const char* frag) void Sprite::setProgramState(backend::ProgramType type) { - if(_programState != nullptr && + setProgramStateWithRegistry(type, _texture); + /*if(_programState != nullptr && _programState->getProgram()->getProgramType() == type) return; auto* program = backend::Program::getBuiltinProgram(type); auto programState = new (std::nothrow) backend::ProgramState(program); setProgramState(programState); - CC_SAFE_RELEASE_NULL(programState); + CC_SAFE_RELEASE_NULL(programState);*/ } void Sprite::setProgramState(backend::ProgramState *programState) @@ -408,17 +409,16 @@ void Sprite::setProgramState(backend::ProgramState *programState) _mvpMatrixLocation = pipelineDescriptor.programState->getUniformLocation(backend::Uniform::MVP_MATRIX); _textureLocation = pipelineDescriptor.programState->getUniformLocation(backend::Uniform::TEXTURE); - _alphaTextureLocation = pipelineDescriptor.programState->getUniformLocation(backend::Uniform::TEXTURE1); setVertexLayout(); - updateProgramStateTexture(); + updateProgramStateTexture(_texture); setMVPMatrixUniform(); } void Sprite::setTexture(Texture2D *texture) { - auto isETC1 = texture && texture->getAlphaTextureName(); - setProgramState((isETC1) ? backend::ProgramType::ETC1 : backend::ProgramType::POSITION_TEXTURE_COLOR); + setProgramStateWithRegistry(backend::ProgramType::POSITION_TEXTURE_COLOR, texture); + CCASSERT(! _batchNode || (texture && texture == _batchNode->getTexture()), "CCSprite: Batched sprites should use the same texture as the batchnode"); // accept texture==nil as argument CCASSERT( !texture || dynamic_cast(texture), "setTexture expects a Texture2D. Invalid argument"); @@ -450,21 +450,7 @@ void Sprite::setTexture(Texture2D *texture) } updateBlendFunc(); } - updateProgramStateTexture(); -} - -void Sprite::updateProgramStateTexture() -{ - if (_texture == nullptr || _texture->getBackendTexture() == nullptr) - return; - - auto programState = _trianglesCommand.getPipelineDescriptor().programState; - programState->setTexture(_textureLocation, 0, _texture->getBackendTexture()); - auto alphaTexture = _texture->getAlphaTexture(); - if(alphaTexture && alphaTexture->getBackendTexture()) - { - programState->setTexture(_alphaTextureLocation, 1, alphaTexture->getBackendTexture()); - } + updateProgramStateTexture(_texture); } Texture2D* Sprite::getTexture() const diff --git a/cocos/2d/CCSprite.h b/cocos/2d/CCSprite.h index 0f0d5c14ab..dff416a240 100644 --- a/cocos/2d/CCSprite.h +++ b/cocos/2d/CCSprite.h @@ -624,7 +624,9 @@ CC_CONSTRUCTOR_ACCESS : virtual void setVertexLayout(); virtual void updateShaders(const char* vert, const char* frag); - + + void setProgramState(backend::ProgramType type); + protected: virtual void updateColor() override; virtual void setTextureCoords(const Rect& rect); @@ -635,13 +637,11 @@ protected: virtual void setDirtyRecursively(bool value); virtual void flipX(); virtual void flipY(); - virtual void updateProgramStateTexture(); void updatePoly(); void updateStretchFactor(); void populateTriangle(int quadIndex, const V3F_C4B_T2F_Quad& quad); void setMVPMatrixUniform(); - void setProgramState(backend::ProgramType type); // // Data used when the sprite is rendered using a SpriteSheet // @@ -664,8 +664,6 @@ protected: backend::UniformLocation _mvpMatrixLocation; backend::UniformLocation _textureLocation; - backend::UniformLocation _alphaTextureLocation; - #if CC_SPRITE_DEBUG_DRAW DrawNode *_debugDrawNode = nullptr; #endif //CC_SPRITE_DEBUG_DRAW diff --git a/cocos/2d/CCSpriteBatchNode.cpp b/cocos/2d/CCSpriteBatchNode.cpp index 5082f4d9b3..6c9c6e0c62 100644 --- a/cocos/2d/CCSpriteBatchNode.cpp +++ b/cocos/2d/CCSpriteBatchNode.cpp @@ -102,42 +102,45 @@ bool SpriteBatchNode::initWithTexture(Texture2D *tex, ssize_t capacity/* = DEFAU _textureAtlas->initWithTexture(tex, capacity); + setProgramStateWithRegistry(backend::ProgramType::POSITION_TEXTURE_COLOR, tex); + updateProgramStateTexture(_textureAtlas->getTexture()); + updateBlendFunc(); _children.reserve(capacity); _descendants.reserve(capacity); - - updateShaders(positionTextureColor_vert, positionTextureColor_frag); - + return true; } -void SpriteBatchNode::updateShaders(const std::string &vertexShader, const std::string &fragmentShader) +void SpriteBatchNode::setProgramState(backend::ProgramState* programState) { auto& pipelineDescriptor = _quadCommand.getPipelineDescriptor(); - auto* program = backend::Device::getInstance()->newProgram(vertexShader, fragmentShader); - CC_SAFE_RELEASE(_programState); - _programState = new (std::nothrow) backend::ProgramState(program); + if (_programState != programState) + { + CC_SAFE_RELEASE(_programState); + _programState = programState; + CC_SAFE_RETAIN(programState); + } pipelineDescriptor.programState = _programState; _mvpMatrixLocaiton = pipelineDescriptor.programState->getUniformLocation("u_MVPMatrix"); _textureLocation = pipelineDescriptor.programState->getUniformLocation("u_texture"); - CC_SAFE_RELEASE(program); - + auto vertexLayout = _programState->getVertexLayout(); const auto& attributeInfo = _programState->getProgram()->getActiveAttributes(); auto iter = attributeInfo.find("a_position"); - if(iter != attributeInfo.end()) + if (iter != attributeInfo.end()) { vertexLayout->setAttribute("a_position", iter->second.location, backend::VertexFormat::FLOAT3, 0, false); } iter = attributeInfo.find("a_texCoord"); - if(iter != attributeInfo.end()) + if (iter != attributeInfo.end()) { vertexLayout->setAttribute("a_texCoord", iter->second.location, backend::VertexFormat::FLOAT2, offsetof(V3F_C4B_T2F, texCoords), false); } iter = attributeInfo.find("a_color"); - if(iter != attributeInfo.end()) + if (iter != attributeInfo.end()) { vertexLayout->setAttribute("a_color", iter->second.location, backend::VertexFormat::UBYTE4, offsetof(V3F_C4B_T2F, colors), true); } @@ -421,7 +424,7 @@ void SpriteBatchNode::draw(Renderer *renderer, const Mat4 &transform, uint32_t f const auto& matrixProjection = Director::getInstance()->getMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION); auto programState = _quadCommand.getPipelineDescriptor().programState; programState->setUniform(_mvpMatrixLocaiton, matrixProjection.m, sizeof(matrixProjection.m)); - programState->setTexture(_textureLocation, 0, _textureAtlas->getTexture()->getBackendTexture()); + // programState->setTexture(_textureLocation, 0, _textureAtlas->getTexture()->getBackendTexture()); _quadCommand.init(_globalZOrder, _textureAtlas->getTexture(), _blendFunc, _textureAtlas->getQuads(), _textureAtlas->getTotalQuads(), transform, flags); renderer->addCommand(&_quadCommand); @@ -681,6 +684,8 @@ Texture2D* SpriteBatchNode::getTexture() const void SpriteBatchNode::setTexture(Texture2D *texture) { _textureAtlas->setTexture(texture); + + updateProgramStateTexture(texture); updateBlendFunc(); } diff --git a/cocos/2d/CCSpriteBatchNode.h b/cocos/2d/CCSpriteBatchNode.h index 1fca0c720e..cc7665f24f 100644 --- a/cocos/2d/CCSpriteBatchNode.h +++ b/cocos/2d/CCSpriteBatchNode.h @@ -259,8 +259,8 @@ protected: void updateAtlasIndex(Sprite* sprite, ssize_t* curIndex); void swap(ssize_t oldIndex, ssize_t newIndex); void updateBlendFunc(); - - virtual void updateShaders(const std::string& vertexShader, const std::string& fragmentShader); + + void setProgramState(backend::ProgramState* programState) override; TextureAtlas *_textureAtlas = nullptr; BlendFunc _blendFunc; @@ -268,7 +268,6 @@ protected: backend::UniformLocation _mvpMatrixLocaiton; backend::UniformLocation _textureLocation; - backend::ProgramState* _programState = nullptr; // all descendants: children, grand children, etc... // There is not need to retain/release these objects, since they are already retained by _children diff --git a/cocos/2d/CCTMXLayer.cpp b/cocos/2d/CCTMXLayer.cpp index f4bc2ee17d..8275fce6a6 100644 --- a/cocos/2d/CCTMXLayer.cpp +++ b/cocos/2d/CCTMXLayer.cpp @@ -249,9 +249,11 @@ void TMXLayer::parseInternalProperties() auto alphaFuncVal = getProperty("cc_alpha_func"); float alphaFuncValue = alphaFuncVal.asFloat(); + setProgramStateWithRegistry(backend::ProgramType::POSITION_TEXTURE_COLOR_ALPHA_TEST, nullptr); + auto& pipelineDescriptor = _quadCommand.getPipelineDescriptor(); auto& vertexShader = pipelineDescriptor.programState->getProgram()->getVertexShader(); - updateShaders(vertexShader, positionTextureColorAlphaTest_frag); + auto alphaValueLocation = pipelineDescriptor.programState->getUniformLocation("u_alpha_value"); pipelineDescriptor.programState->setUniform(alphaValueLocation, &alphaFuncValue, sizeof(alphaFuncValue)); } diff --git a/cocos/base/ccConfig.h b/cocos/base/ccConfig.h index 8c1df270c3..63553c9a21 100644 --- a/cocos/base/ccConfig.h +++ b/cocos/base/ccConfig.h @@ -357,3 +357,7 @@ THE SOFTWARE. #ifndef CC_STRIP_FPS #define CC_STRIP_FPS 0 #endif + +#ifndef CC_META_TEXTURES +#define CC_META_TEXTURES 2 +#endif diff --git a/cocos/editor-support/cocostudio/ActionTimeline/CCBoneNode.h b/cocos/editor-support/cocostudio/ActionTimeline/CCBoneNode.h index aadf34f7af..eab7d9e8fe 100644 --- a/cocos/editor-support/cocostudio/ActionTimeline/CCBoneNode.h +++ b/cocos/editor-support/cocostudio/ActionTimeline/CCBoneNode.h @@ -208,7 +208,6 @@ protected: void setRootSkeleton(BoneNode* bone, SkeletonNode* skeleton) const; protected: cocos2d::CustomCommand _customCommand; - cocos2d::backend::ProgramState* _programState = nullptr; cocos2d::backend::UniformLocation _mvpLocation; cocos2d::BlendFunc _blendFunc = cocos2d::BlendFunc::ALPHA_NON_PREMULTIPLIED; diff --git a/cocos/platform/CCImage.cpp b/cocos/platform/CCImage.cpp index 5fdc3a3dc3..fca147a437 100644 --- a/cocos/platform/CCImage.cpp +++ b/cocos/platform/CCImage.cpp @@ -30,7 +30,6 @@ THE SOFTWARE. #include #include -#include "base/CCData.h" #include "base/ccConfig.h" // CC_USE_JPEG, CC_USE_WEBP #include "platform/CCGL.h" @@ -481,6 +480,7 @@ bool Image::PNG_PREMULTIPLIED_ALPHA_ENABLED = true; Image::Image() : _data(nullptr) , _dataLen(0) +, _offset(0) , _width(0) , _height(0) , _unpack(false) @@ -512,7 +512,9 @@ bool Image::initWithImageFile(const std::string& path) if (!data.isNull()) { - ret = initWithImageData(data.getBytes(), data.getSize()); + ssize_t n = 0; + auto buf = data.takeBuffer(&n); + ret = initWithImageData(buf, n, true); } return ret; @@ -527,19 +529,21 @@ bool Image::initWithImageFileThreadSafe(const std::string& fullpath) if (!data.isNull()) { - ret = initWithImageData(data.getBytes(), data.getSize()); + ssize_t n = 0; + auto buf = data.takeBuffer(&n); + ret = initWithImageData(buf, n, true); } return ret; } -bool Image::initWithImageData(const unsigned char * data, ssize_t dataLen) +bool Image::initWithImageData(const unsigned char* data, ssize_t dataLen, bool ownData) { bool ret = false; do { - CC_BREAK_IF(! data || dataLen <= 0); + CC_BREAK_IF(!data || dataLen == 0); unsigned char* unpackedData = nullptr; ssize_t unpackedLen = 0; @@ -576,7 +580,7 @@ bool Image::initWithImageData(const unsigned char * data, ssize_t dataLen) ret = initWithPVRData(unpackedData, unpackedLen); break; case Format::ETC: - ret = initWithETCData(unpackedData, unpackedLen); + ret = initWithETCData(unpackedData, unpackedLen, ownData); break; case Format::S3TC: ret = initWithS3TCData(unpackedData, unpackedLen); @@ -1421,7 +1425,7 @@ bool Image::initWithPVRv3Data(const unsigned char * data, ssize_t dataLen) return true; } -bool Image::initWithETCData(const unsigned char * data, ssize_t dataLen) +bool Image::initWithETCData(const unsigned char* data, ssize_t dataLen, bool ownData) { const etc1_byte* header = static_cast(data); @@ -1439,23 +1443,26 @@ bool Image::initWithETCData(const unsigned char * data, ssize_t dataLen) return false; } + // pitfall: because we do merge etc1 alpha at shader, so must mark as _hasPremultipliedAlpha=true to makesure alpha blend works well. + // the Premultiply operation can only do at shader. + _hasPremultipliedAlpha = true; + if (Configuration::getInstance()->supportsETC()) { //old opengl version has no define for GL_ETC1_RGB8_OES, add macro to make compiler happy. #if defined(GL_ETC1_RGB8_OES) || defined(CC_USE_METAL) _pixelFormat = backend::PixelFormat::ETC; - _dataLen = dataLen - ETC_PKM_HEADER_SIZE; - _data = static_cast(malloc(_dataLen * sizeof(unsigned char))); - memcpy(_data, static_cast(data) + ETC_PKM_HEADER_SIZE, _dataLen); + _data = data; + _dataLen = dataLen; + _offset = ETC_PKM_HEADER_SIZE; return true; -#else - CC_UNUSED_PARAM(dataLen); #endif } else { CCLOG("cocos2d: Hardware ETC1 decoder not present. Using software decoder"); + bool ret = true; //if it is not gles or device do not support ETC, decode texture by software int bytePerPixel = 3; unsigned int stride = _width * bytePerPixel; @@ -1470,12 +1477,16 @@ bool Image::initWithETCData(const unsigned char * data, ssize_t dataLen) if (_data != nullptr) { free(_data); + _data = nullptr; } - return false; + ret = false; } - - return true; + + if (ownData) free((void*)data); + return ret; } + + if (ownData) free((void*)data); return false; } diff --git a/cocos/platform/CCImage.h b/cocos/platform/CCImage.h index ce789ee1af..d0a9fe742d 100644 --- a/cocos/platform/CCImage.h +++ b/cocos/platform/CCImage.h @@ -30,6 +30,7 @@ THE SOFTWARE. #include "base/CCRef.h" #include "renderer/CCTexture2D.h" +#include "base/CCData.h" // premultiply alpha, or the effect will be wrong when using other pixel formats in Texture2D, // such as RGB888, RGB5A1 @@ -125,14 +126,14 @@ public: * @js NA * @lua NA */ - bool initWithImageData(const unsigned char * data, ssize_t dataLen); + bool initWithImageData(const unsigned char * data, ssize_t dataLen, bool ownData = false); // @warning kFmtRawData only support RGBA8888 bool initWithRawData(const unsigned char * data, ssize_t dataLen, int width, int height, int bitsPerComponent, bool preMulti = false); // Getters - unsigned char * getData() { return _data; } - ssize_t getDataLen() { return _dataLen; } + unsigned char * getData() { return _data + _offset; } + ssize_t getDataLen() { return _dataLen - _offset; } Format getFileType() { return _fileType; } backend::PixelFormat getPixelFormat() { return _pixelFormat; } int getWidth() { return _width; } @@ -163,7 +164,7 @@ protected: bool initWithPVRData(const unsigned char * data, ssize_t dataLen); bool initWithPVRv2Data(const unsigned char * data, ssize_t dataLen); bool initWithPVRv3Data(const unsigned char * data, ssize_t dataLen); - bool initWithETCData(const unsigned char * data, ssize_t dataLen); + bool initWithETCData(const unsigned char* data, ssize_t dataLen, bool ownData); bool initWithS3TCData(const unsigned char * data, ssize_t dataLen); bool initWithATITCData(const unsigned char *data, ssize_t dataLen); typedef struct sImageTGA tImageTGA; @@ -186,6 +187,7 @@ protected: static bool PNG_PREMULTIPLIED_ALPHA_ENABLED; unsigned char *_data; ssize_t _dataLen; + ssize_t _offset; int _width; int _height; bool _unpack; diff --git a/cocos/renderer/CCQuadCommand.cpp b/cocos/renderer/CCQuadCommand.cpp index 286093b50f..4e6018d1c0 100644 --- a/cocos/renderer/CCQuadCommand.cpp +++ b/cocos/renderer/CCQuadCommand.cpp @@ -97,8 +97,6 @@ void QuadCommand::init(float globalOrder, Texture2D *texture, const BlendFunc& b triangles.indices = __indices; triangles.indexCount = (int)quadCount * 6; TrianglesCommand::init(globalOrder, texture, blendType, triangles, mv, flags); - - _alphaTextureID = texture->getAlphaTextureName(); } NS_CC_END diff --git a/cocos/renderer/CCTexture2D.cpp b/cocos/renderer/CCTexture2D.cpp index 7d6699a056..62bca1a158 100644 --- a/cocos/renderer/CCTexture2D.cpp +++ b/cocos/renderer/CCTexture2D.cpp @@ -137,7 +137,6 @@ Texture2D::Texture2D() , _antialiasEnabled(true) , _ninePatchInfo(nullptr) , _valid(true) -, _alphaTexture(nullptr) { backend::TextureDescriptor textureDescriptor; textureDescriptor.textureFormat = PixelFormat::NONE; @@ -149,8 +148,6 @@ Texture2D::~Texture2D() #if CC_ENABLE_CACHE_TEXTURE_DATA VolatileTextureMgr::removeTexture(this); #endif - CC_SAFE_RELEASE_NULL(_alphaTexture); // ETC1 ALPHA support. - CCLOGINFO("deallocing Texture2D: %p - id=%u", this, _name); CC_SAFE_DELETE(_ninePatchInfo); @@ -179,11 +176,6 @@ backend::TextureBackend* Texture2D::getBackendTexture() const return _texture; } -bool Texture2D::getAlphaTextureName() const -{ - return _alphaTexture == nullptr ? 0 : _alphaTexture->getBackendTexture(); -} - Size Texture2D::getContentSize() const { Size ret; @@ -235,6 +227,128 @@ bool Texture2D::initWithData(const void *data, ssize_t dataLen, backend::PixelFo } bool Texture2D::initWithMipmaps(MipmapInfo* mipmaps, int mipmapsNum, backend::PixelFormat pixelFormat, backend::PixelFormat renderFormat, int pixelsWide, int pixelsHigh, bool preMultipliedAlpha) +{ + //the pixelFormat must be a certain value + updateWithMipmaps(mipmaps, mipmapsNum, pixelFormat, renderFormat, pixelsWide, pixelsHigh, preMultipliedAlpha); + + return true; +} + +bool Texture2D::updateWithImage(Image* image, backend::PixelFormat format, int index) +{ + if (image == nullptr) + { + CCLOG("cocos2d: Texture2D. Can't create Texture. UIImage is nil"); + return false; + } + + if(this->_filePath.empty()) this->_filePath = image->getFilePath(); + + int imageWidth = image->getWidth(); + int imageHeight = image->getHeight(); + + Configuration* conf = Configuration::getInstance(); + + int maxTextureSize = conf->getMaxTextureSize(); + if (imageWidth > maxTextureSize || imageHeight > maxTextureSize) + { + CCLOG("cocos2d: WARNING: Image (%u x %u) is bigger than the supported %u x %u", imageWidth, imageHeight, maxTextureSize, maxTextureSize); + return false; + } + + unsigned char* tempData = image->getData(); + Size imageSize = Size((float)imageWidth, (float)imageHeight); + backend::PixelFormat renderFormat = ((PixelFormat::NONE == format) || (PixelFormat::AUTO == format)) ? image->getPixelFormat() : format; + backend::PixelFormat imagePixelFormat = image->getPixelFormat(); + size_t tempDataLen = image->getDataLen(); + + +#ifdef CC_USE_METAL + //compressed format does not need conversion + switch (imagePixelFormat) { + case PixelFormat::PVRTC4A: + case PixelFormat::PVRTC4: + case PixelFormat::PVRTC2A: + case PixelFormat::PVRTC2: + case PixelFormat::A8: + renderFormat = imagePixelFormat; + default: + break; + } + //override renderFormat, since some render format is not supported by metal + switch (renderFormat) + { +#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS && !TARGET_OS_SIMULATOR) + //packed 16 bits pixels only available on iOS + case PixelFormat::RGB565: + renderFormat = PixelFormat::MTL_B5G6R5; + break; + case PixelFormat::RGBA4444: + renderFormat = PixelFormat::MTL_ABGR4; + break; + case PixelFormat::RGB5A1: + renderFormat = PixelFormat::MTL_BGR5A1; + break; +#else + case PixelFormat::RGB565: + case PixelFormat::RGB5A1: + case PixelFormat::RGBA4444: +#endif + case PixelFormat::I8: + case PixelFormat::AI88: + //TODO: conversion RGBA8888 -> I8(AI88) -> RGBA8888 may happends + renderFormat = PixelFormat::RGBA8888; + break; + default: + break; + } +#endif + + if (image->getNumberOfMipmaps() > 1) + { + if (renderFormat != image->getPixelFormat()) + { + CCLOG("cocos2d: WARNING: This image has more than 1 mipmaps and we will not convert the data format"); + } + + //pixel format of data is not converted, renderFormat can be different from pixelFormat + //it will be done later + updateWithMipmaps(image->getMipmaps(), image->getNumberOfMipmaps(), image->getPixelFormat(), renderFormat, imageWidth, imageHeight, image->hasPremultipliedAlpha(), index); + + return true; + } + else if (image->isCompressed()) + { + if (renderFormat != image->getPixelFormat()) + { + CCLOG("cocos2d: WARNING: This image is compressed and we can't convert it for now"); + } + + updateWithData(tempData, tempDataLen, image->getPixelFormat(), image->getPixelFormat(), imageWidth, imageHeight, imageSize, image->hasPremultipliedAlpha(), index); + + return true; + } + else + { + //after conversion, renderFormat == pixelFormat of data + updateWithData(tempData, tempDataLen, imagePixelFormat, renderFormat, imageWidth, imageHeight, imageSize, image->hasPremultipliedAlpha(), index); + + return true; + } +} + +bool Texture2D::updateWithData(const void* data, ssize_t dataLen, backend::PixelFormat pixelFormat, backend::PixelFormat renderFormat, int pixelsWide, int pixelsHigh, const Size& /*contentSize*/, bool preMultipliedAlpha, int index) +{ + CCASSERT(dataLen > 0 && pixelsWide > 0 && pixelsHigh > 0, "Invalid size"); + + //if data has no mipmaps, we will consider it has only one mipmap + MipmapInfo mipmap; + mipmap.address = (unsigned char*)data; + mipmap.len = static_cast(dataLen); + return updateWithMipmaps(&mipmap, 1, pixelFormat, renderFormat, pixelsWide, pixelsHigh, preMultipliedAlpha, index); +} + +bool Texture2D::updateWithMipmaps(MipmapInfo* mipmaps, int mipmapsNum, backend::PixelFormat pixelFormat, backend::PixelFormat renderFormat, int pixelsWide, int pixelsHigh, bool preMultipliedAlpha, int index) { //the pixelFormat must be a certain value CCASSERT(pixelFormat != PixelFormat::NONE && pixelFormat != PixelFormat::AUTO, "the \"pixelFormat\" param must be a certain value!"); @@ -271,7 +385,7 @@ bool Texture2D::initWithMipmaps(MipmapInfo* mipmaps, int mipmapsNum, backend::Pi #if CC_ENABLE_CACHE_TEXTURE_DATA VolatileTextureMgr::findVolotileTexture(this); #endif - + backend::TextureDescriptor textureDescriptor; textureDescriptor.width = pixelsWide; textureDescriptor.height = pixelsHigh; @@ -290,70 +404,70 @@ bool Texture2D::initWithMipmaps(MipmapInfo* mipmaps, int mipmapsNum, backend::Pi backend::PixelFormat oriPixelFormat = pixelFormat; for (int i = 0; i < mipmapsNum; ++i) { - unsigned char *data = mipmaps[i].address; + unsigned char* data = mipmaps[i].address; size_t dataLen = mipmaps[i].len; - unsigned char *outData = data; + unsigned char* outData = data; size_t outDataLen = dataLen; - if(renderFormat != oriPixelFormat && !info.compressed) //need conversion + if (renderFormat != oriPixelFormat && !info.compressed) //need conversion { auto convertedFormat = backend::PixelFormatUtils::convertDataToFormat(data, dataLen, oriPixelFormat, renderFormat, &outData, &outDataLen); #ifdef CC_USE_METAL CCASSERT(convertedFormat == renderFormat, "PixelFormat convert failed!"); #endif - if(convertedFormat == renderFormat) pixelFormat = renderFormat; + if (convertedFormat == renderFormat) pixelFormat = renderFormat; } - + textureDescriptor.textureFormat = pixelFormat; CCASSERT(textureDescriptor.textureFormat != backend::PixelFormat::NONE, "PixelFormat should not be NONE"); - if(_texture->getTextureFormat() != textureDescriptor.textureFormat) - _texture->updateTextureDescriptor(textureDescriptor); + if (_texture->getTextureFormat() != textureDescriptor.textureFormat) + _texture->updateTextureDescriptor(textureDescriptor, index); - if(info.compressed) + if (info.compressed) { _texture->updateCompressedData(data, width, height, dataLen, i); } else { - _texture->updateData(outData, width, height, i); + _texture->updateData(outData, width, height, i, index); } - if(outData && outData != data && outDataLen > 0) + if (outData && outData != data && outDataLen > 0) { free(outData); outData = nullptr; outDataLen = 0; } - - if (i > 0 && (width != height || ccNextPOT(width) != width )) + + if (i > 0 && (width != height || ccNextPOT(width) != width)) { CCLOG("cocos2d: Texture2D. WARNING. Mipmap level %u is not squared. Texture won't render correctly. width=%d != height=%d", i, width, height); } - + width = MAX(width >> 1, 1); height = MAX(height >> 1, 1); } - - _contentSize = Size((float)pixelsWide, (float)pixelsHigh); - _pixelsWide = pixelsWide; - _pixelsHigh = pixelsHigh; - _pixelFormat = pixelFormat; - _maxS = 1; - _maxT = 1; - _hasPremultipliedAlpha = preMultipliedAlpha; - _hasMipmaps = mipmapsNum > 1; + if (index == 0) { + _contentSize = Size((float)pixelsWide, (float)pixelsHigh); + _pixelsWide = pixelsWide; + _pixelsHigh = pixelsHigh; + _pixelFormat = pixelFormat; + _maxS = 1; + _maxT = 1; - return true; + _hasPremultipliedAlpha = preMultipliedAlpha; + _hasMipmaps = mipmapsNum > 1; + } } -bool Texture2D::updateWithData(void *data,int offsetX,int offsetY,int width,int height) +bool Texture2D::updateWithSubData(void *data,int offsetX,int offsetY,int width,int height, int index) { if (_texture && width > 0 && height > 0) { uint8_t* textureData = static_cast(data); - _texture->updateSubData(offsetX, offsetY, width, height, 0, textureData); + _texture->updateSubData(offsetX, offsetY, width, height, 0, textureData, index); return true; } return false; @@ -373,97 +487,9 @@ bool Texture2D::initWithImage(Image *image, backend::PixelFormat format) return false; } - int imageWidth = image->getWidth(); - int imageHeight = image->getHeight(); this->_filePath = image->getFilePath(); - Configuration *conf = Configuration::getInstance(); - int maxTextureSize = conf->getMaxTextureSize(); - if (imageWidth > maxTextureSize || imageHeight > maxTextureSize) - { - CCLOG("cocos2d: WARNING: Image (%u x %u) is bigger than the supported %u x %u", imageWidth, imageHeight, maxTextureSize, maxTextureSize); - return false; - } - - unsigned char* tempData = image->getData(); - Size imageSize = Size((float)imageWidth, (float)imageHeight); - backend::PixelFormat renderFormat = ((PixelFormat::NONE == format) || (PixelFormat::AUTO == format)) ? image->getPixelFormat() : format; - backend::PixelFormat imagePixelFormat = image->getPixelFormat(); - size_t tempDataLen = image->getDataLen(); - - -#ifdef CC_USE_METAL - //compressed format does not need conversion - switch (imagePixelFormat) { - case PixelFormat::PVRTC4A: - case PixelFormat::PVRTC4: - case PixelFormat::PVRTC2A: - case PixelFormat::PVRTC2: - case PixelFormat::A8: - renderFormat = imagePixelFormat; - default: - break; - } - //override renderFormat, since some render format is not supported by metal - switch (renderFormat) - { -#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS && !TARGET_OS_SIMULATOR) - //packed 16 bits pixels only available on iOS - case PixelFormat::RGB565: - renderFormat = PixelFormat::MTL_B5G6R5; - break; - case PixelFormat::RGBA4444: - renderFormat = PixelFormat::MTL_ABGR4; - break; - case PixelFormat::RGB5A1: - renderFormat = PixelFormat::MTL_BGR5A1; - break; -#else - case PixelFormat::RGB565: - case PixelFormat::RGB5A1: - case PixelFormat::RGBA4444: -#endif - case PixelFormat::I8: - case PixelFormat::AI88: - //TODO: conversion RGBA8888 -> I8(AI88) -> RGBA8888 may happends - renderFormat = PixelFormat::RGBA8888; - break; - default: - break; - } -#endif - - if (image->getNumberOfMipmaps() > 1) - { - if (renderFormat != image->getPixelFormat()) - { - CCLOG("cocos2d: WARNING: This image has more than 1 mipmaps and we will not convert the data format"); - } - - //pixel format of data is not converted, renderFormat can be different from pixelFormat - //it will be done later - initWithMipmaps(image->getMipmaps(), image->getNumberOfMipmaps(), image->getPixelFormat(), renderFormat, imageWidth, imageHeight, image->hasPremultipliedAlpha()); - - return true; - } - else if (image->isCompressed()) - { - if (renderFormat != image->getPixelFormat()) - { - CCLOG("cocos2d: WARNING: This image is compressed and we can't convert it for now"); - } - - initWithData(tempData, tempDataLen, image->getPixelFormat(), imageWidth, imageHeight, imageSize, image->hasPremultipliedAlpha()); - - return true; - } - else - { - //after conversion, renderFormat == pixelFormat of data - initWithData(tempData, tempDataLen, imagePixelFormat, renderFormat, imageWidth, imageHeight, imageSize, image->hasPremultipliedAlpha()); - - return true; - } + return updateWithImage(image, format); } // implementation Texture2D (Text) @@ -792,22 +818,6 @@ void Texture2D::removeSpriteFrameCapInset(SpriteFrame* spriteFrame) } } -/// halx99 spec, ANDROID ETC1 ALPHA supports. -void Texture2D::setAlphaTexture(Texture2D* alphaTexture) -{ - if (alphaTexture != nullptr) { - alphaTexture->retain(); - CC_SAFE_RELEASE(_alphaTexture); - _alphaTexture = alphaTexture; - _hasPremultipliedAlpha = true; // PremultipliedAlpha should be true. - } -} - -Texture2D* Texture2D::getAlphaTexture() const -{ - return _alphaTexture; -} - void Texture2D::setTexParameters(const Texture2D::TexParams &desc) { _texture->updateSamplerDescriptor(desc); diff --git a/cocos/renderer/CCTexture2D.h b/cocos/renderer/CCTexture2D.h index 7dc2b81e2c..915e51e91c 100644 --- a/cocos/renderer/CCTexture2D.h +++ b/cocos/renderer/CCTexture2D.h @@ -170,6 +170,18 @@ public: */ bool initWithMipmaps(MipmapInfo* mipmaps, int mipmapsNum, backend::PixelFormat pixelFormat, backend::PixelFormat renderFormat, int pixelsWide, int pixelsHigh, bool preMultipliedAlpha = false); + /** Update with image. + + @param data Specifies a pointer to the image data in memory. + @param offsetX Specifies a texel offset in the x direction within the texture array. + @param offsetY Specifies a texel offset in the y direction within the texture array. + @param width Specifies the width of the texture subimage. + @param height Specifies the height of the texture subimage. + */ + bool updateWithImage(Image* image, backend::PixelFormat format, int index = 0); + bool updateWithData(const void* data, ssize_t dataLen, backend::PixelFormat pixelFormat, backend::PixelFormat renderFormat, int pixelsWide, int pixelsHigh, const Size& /*contentSize*/, bool preMultipliedAlpha, int index = 0); + bool updateWithMipmaps(MipmapInfo* mipmaps, int mipmapsNum, backend::PixelFormat pixelFormat, backend::PixelFormat renderFormat, int pixelsWide, int pixelsHigh, bool preMultipliedAlpha = false, int index = 0); + /** Update with texture data. @param data Specifies a pointer to the image data in memory. @@ -178,7 +190,7 @@ public: @param width Specifies the width of the texture subimage. @param height Specifies the height of the texture subimage. */ - bool updateWithData(void *data,int offsetX,int offsetY,int width,int height); + bool updateWithSubData(void *data,int offsetX,int offsetY,int width,int height, int index = 0); /** Drawing extensions to make it easy to draw basic quads using a Texture2D object. These functions require GL_TEXTURE_2D and both GL_VERTEX_ARRAY and GL_TEXTURE_COORD_ARRAY client states to be enabled. @@ -313,11 +325,6 @@ public: Size getContentSize() const; std::string getPath()const { return _filePath; } - - void setAlphaTexture(Texture2D* alphaTexture); - Texture2D* getAlphaTexture() const; - - bool getAlphaTextureName() const; public: /** Get pixel info map, the key-value pairs is PixelFormat and PixelFormatInfo.*/ @@ -409,7 +416,6 @@ protected: bool _valid; std::string _filePath; - Texture2D* _alphaTexture; backend::ProgramState* _programState = nullptr; backend::UniformLocation _mvpMatrixLocation; backend::UniformLocation _textureLocation; diff --git a/cocos/renderer/CCTextureCache.cpp b/cocos/renderer/CCTextureCache.cpp index 8160c4a338..28c99a1dfc 100644 --- a/cocos/renderer/CCTextureCache.cpp +++ b/cocos/renderer/CCTextureCache.cpp @@ -348,11 +348,7 @@ void TextureCache::addImageAsyncCallBack(float /*dt*/) texture->autorelease(); // ETC1 ALPHA supports. if (asyncStruct->imageAlpha.getFileType() == Image::Format::ETC) { - auto alphaTexture = new(std::nothrow) Texture2D(); - if(alphaTexture != nullptr && alphaTexture->initWithImage(&asyncStruct->imageAlpha, asyncStruct->pixelFormat)) { - texture->setAlphaTexture(alphaTexture); - } - CC_SAFE_RELEASE(alphaTexture); + texture->updateWithImage(&asyncStruct->imageAlpha, Texture2D::getDefaultAlphaPixelFormat(), 1); } } else { @@ -421,14 +417,10 @@ Texture2D * TextureCache::addImage(const std::string &path) std::string alphaFullPath = path + s_etc1AlphaFileSuffix; if (image->getFileType() == Image::Format::ETC && !s_etc1AlphaFileSuffix.empty() && FileUtils::getInstance()->isFileExist(alphaFullPath)) { - Image alphaImage; - if (alphaImage.initWithImageFile(alphaFullPath)) + Image imageAlpha; + if (imageAlpha.initWithImageFile(alphaFullPath)) { - Texture2D *pAlphaTexture = new(std::nothrow) Texture2D; - if(pAlphaTexture != nullptr && pAlphaTexture->initWithImage(&alphaImage)) { - texture->setAlphaTexture(pAlphaTexture); - } - CC_SAFE_RELEASE(pAlphaTexture); + texture->updateWithImage(&imageAlpha, Texture2D::getDefaultAlphaPixelFormat(), 1); } } diff --git a/cocos/renderer/CCTrianglesCommand.h b/cocos/renderer/CCTrianglesCommand.h index 8cc7fc5e67..3379339357 100644 --- a/cocos/renderer/CCTrianglesCommand.h +++ b/cocos/renderer/CCTrianglesCommand.h @@ -114,8 +114,6 @@ protected: /**Model view matrix when rendering the triangles.*/ Mat4 _mv; - uint8_t _alphaTextureID = 0; // ANDROID ETC1 ALPHA supports. - // Cached value to determine to generate material id or not. BlendFunc _blendType = BlendFunc::DISABLE; backend::Program* _program = nullptr; diff --git a/cocos/renderer/CMakeLists.txt b/cocos/renderer/CMakeLists.txt index d84c90d768..904ad445d7 100644 --- a/cocos/renderer/CMakeLists.txt +++ b/cocos/renderer/CMakeLists.txt @@ -36,6 +36,7 @@ set(COCOS_RENDERER_HEADER renderer/backend/Types.h renderer/backend/VertexLayout.h renderer/backend/ProgramState.h + renderer/backend/ProgramStateRegistry.h renderer/backend/ShaderCache.h renderer/backend/DeviceInfo.h ) @@ -70,6 +71,7 @@ set(COCOS_RENDERER_SRC renderer/backend/ProgramCache.cpp renderer/backend/Program.cpp renderer/backend/ProgramState.cpp + renderer/backend/ProgramStateRegistry.cpp renderer/backend/ShaderCache.cpp renderer/backend/RenderPassDescriptor.cpp ) diff --git a/cocos/renderer/backend/ProgramCache.cpp b/cocos/renderer/backend/ProgramCache.cpp index 0166a3724d..b6e9b7e98e 100644 --- a/cocos/renderer/backend/ProgramCache.cpp +++ b/cocos/renderer/backend/ProgramCache.cpp @@ -29,20 +29,6 @@ #include "base/ccMacros.h" #include "base/CCConfiguration.h" -namespace std -{ - template <> - struct hash - { - typedef cocos2d::backend::ProgramType argument_type; - typedef std::size_t result_type; - result_type operator()(argument_type const& v) const - { - return hash()(static_cast(v)); - } - }; -} - CC_BACKEND_BEGIN namespace @@ -126,6 +112,16 @@ bool ProgramCache::init() addProgram(ProgramType::TERRAIN_3D); addProgram(ProgramType::PARTICLE_TEXTURE_3D); addProgram(ProgramType::PARTICLE_COLOR_3D); + + /* FIXME: Naming style + ** ETC1: POSITION_TEXTURE_COLOR_ETC1 + ** GRAY_SCALE maybe: POSITION_TEXTURE_COLOR_GRAY + ** ETC1_GRAY maybe: POSITION_TEXTURE_COLOR_GRAY_ETC1 + */ + ProgramStateRegistry::getInstance()->registerProgram(ProgramType::POSITION_TEXTURE_COLOR, 2, + getBuiltinProgram(ProgramType::ETC1)); + ProgramStateRegistry::getInstance()->registerProgram(ProgramType::GRAY_SCALE, 2, + getBuiltinProgram(ProgramType::ETC1_GRAY)); return true; } @@ -298,6 +294,7 @@ void ProgramCache::removeUnusedProgram() void ProgramCache::removeAllPrograms() { + ProgramStateRegistry::getInstance()->clearPrograms(); for (auto& program : _cachedPrograms) { program.second->release(); diff --git a/cocos/renderer/backend/ProgramCache.h b/cocos/renderer/backend/ProgramCache.h index 71a3d0e4a0..0626df6d0f 100644 --- a/cocos/renderer/backend/ProgramCache.h +++ b/cocos/renderer/backend/ProgramCache.h @@ -32,6 +32,8 @@ #include #include +#include "ProgramStateRegistry.h" + CC_BACKEND_BEGIN /** * @addtogroup _backend diff --git a/cocos/renderer/backend/ProgramState.cpp b/cocos/renderer/backend/ProgramState.cpp index 878d8c5b6d..062b809ff0 100644 --- a/cocos/renderer/backend/ProgramState.cpp +++ b/cocos/renderer/backend/ProgramState.cpp @@ -381,6 +381,14 @@ void ProgramState::setFragmentUniform(int location, const void* data, std::size_ #endif } +void ProgramState::setTexture(backend::TextureBackend* texture) +{ + for (int index = 0; index < texture->getCount() && index < CC_META_TEXTURES; ++index) { + auto location = getUniformLocation((backend::Uniform)(backend::Uniform::TEXTURE + index)); + setTexture(location, index, texture); + } +} + void ProgramState::setTexture(const backend::UniformLocation& uniformLocation, uint32_t slot, backend::TextureBackend* texture) { switch (uniformLocation.shaderStage) diff --git a/cocos/renderer/backend/ProgramState.h b/cocos/renderer/backend/ProgramState.h index ff45a25dab..91cff2fe74 100644 --- a/cocos/renderer/backend/ProgramState.h +++ b/cocos/renderer/backend/ProgramState.h @@ -142,6 +142,14 @@ public: */ void setCallbackUniform(const backend::UniformLocation&, const UniformCallback &); + /** + * Set texture. + * @param uniformLocation Specifies texture location. + * @param slot Specifies texture slot selector. + * @param texture Specifies a pointer to backend texture. + */ + void setTexture(backend::TextureBackend* texture); + /** * Set texture. * @param uniformLocation Specifies texture location. diff --git a/cocos/renderer/backend/ProgramStateRegistry.cpp b/cocos/renderer/backend/ProgramStateRegistry.cpp new file mode 100644 index 0000000000..59cb02cb1b --- /dev/null +++ b/cocos/renderer/backend/ProgramStateRegistry.cpp @@ -0,0 +1,81 @@ +#pragma once + +#include "ProgramStateRegistry.h" + +CC_BACKEND_BEGIN + +static ProgramStateRegistry* _sharedStateRegistry = nullptr; +/** returns the shared instance */ +ProgramStateRegistry* ProgramStateRegistry::getInstance() +{ + if (_sharedStateRegistry) + return _sharedStateRegistry; + + _sharedStateRegistry = new (std::nothrow) ProgramStateRegistry(); + if (!_sharedStateRegistry->init()) + { + CC_SAFE_RELEASE_NULL(_sharedStateRegistry); + } + + return _sharedStateRegistry; +} + +/** purges the cache. It releases the retained instance. */ +void ProgramStateRegistry::destroyInstance() +{ + CC_SAFE_RELEASE_NULL(_sharedStateRegistry); +} + +bool ProgramStateRegistry::init() +{ + return true; +} + +void ProgramStateRegistry::registerProgram(ProgramType programType, int maxCount, Program* program) +{ + auto maxIndex = maxCount - 1; + auto it = this->_registry.find(programType); + if (it == this->_registry.end()) { + it = this->_registry.emplace(programType, std::vector{}).first; + it->second.resize(CC_META_TEXTURES); + } + if (maxIndex < it->second.size()) + it->second[maxIndex] = program; +} + +void ProgramStateRegistry::clearPrograms() { + this->_registry.clear(); +} + +ProgramState* ProgramStateRegistry::getProgramState(ProgramType programType, int maxCount) +{ + auto maxIndex = maxCount - 1; + auto it = this->_registry.find(programType); + if (it != this->_registry.end() && it->second.size() > maxIndex) { + auto fallback = it->second[maxIndex]; + if (fallback) + return new(std::nothrow) ProgramState(fallback); + } + + return new(std::nothrow) ProgramState(Program::getBuiltinProgram((ProgramType)programType)); +} + +ProgramType ProgramStateRegistry::getProgramType(ProgramType programType, TextureBackend* texture2d) +{ + return this->getProgramType(programType, texture2d->getCount()); +} + +ProgramType ProgramStateRegistry::getProgramType(ProgramType programType, int maxCount) +{ + auto maxIndex = maxCount - 1; + auto it = this->_registry.find(programType); + if (it != this->_registry.end() && it->second.size() > maxIndex) { + auto fallback = it->second[maxIndex]; + if (fallback) + return fallback->getProgramType(); + } + return programType; +} +//end of _backend group +/// @} +CC_BACKEND_END diff --git a/cocos/renderer/backend/ProgramStateRegistry.h b/cocos/renderer/backend/ProgramStateRegistry.h new file mode 100644 index 0000000000..a04973d76f --- /dev/null +++ b/cocos/renderer/backend/ProgramStateRegistry.h @@ -0,0 +1,62 @@ +#pragma once +#include "Macros.h" +#include "base/CCRef.h" +#include "platform/CCPlatformMacros.h" +#include "Program.h" +#include "ProgramState.h" + +#include +#include + +namespace std +{ + template <> + struct hash + { + typedef cocos2d::backend::ProgramType argument_type; + typedef std::size_t result_type; + result_type operator()(argument_type const& v) const + { + return hash()(static_cast(v)); + } + }; +}; + +CC_BACKEND_BEGIN +/** + * @addtogroup _backend + * @{ + * #todo: Rename to ProgramStateRegistry + */ +/* + Group by programType and texIndex + default, we register: + programType = positionTextureColor, texIndex = 0 ---> positionTextureColorDefault + programType = positionTextureColor, texIndex = 1 ---> positionTextureColorDualETC1 + +*/ +class ProgramStateRegistry : public Ref { +public: + /** returns the shared instance */ + static ProgramStateRegistry* getInstance(); + + /** purges the cache. It releases the retained instance. */ + static void destroyInstance(); + + bool init(); + + void registerProgram(ProgramType programType, int maxCount, Program*); + void clearPrograms(); + ProgramState* getProgramState(ProgramType programType, int maxCount); + + ProgramType getProgramType(ProgramType programType, TextureBackend* texture2d); + ProgramType getProgramType(ProgramType programType, int maxCount); + +protected: + + std::unordered_map> _registry; +}; + +//end of _backend group +/// @} +CC_BACKEND_END diff --git a/cocos/renderer/backend/Texture.cpp b/cocos/renderer/backend/Texture.cpp index 68bd973b48..0e712a0a52 100644 --- a/cocos/renderer/backend/Texture.cpp +++ b/cocos/renderer/backend/Texture.cpp @@ -107,7 +107,7 @@ TextureBackend::TextureBackend(const TextureDescriptor& descriptor) TextureBackend::~TextureBackend() {} -void TextureBackend::updateTextureDescriptor(const cocos2d::backend::TextureDescriptor &descriptor) +void TextureBackend::updateTextureDescriptor(const cocos2d::backend::TextureDescriptor &descriptor, int /*index*/) { _bitsPerElement = computeBitsPerElement(descriptor.textureFormat); _textureType = descriptor.textureType; diff --git a/cocos/renderer/backend/Texture.h b/cocos/renderer/backend/Texture.h index bd8435cafc..b4ec78fc41 100644 --- a/cocos/renderer/backend/Texture.h +++ b/cocos/renderer/backend/Texture.h @@ -60,7 +60,7 @@ public: * Update sampler * @param sampler Specifies the sampler descriptor. */ - virtual void updateSamplerDescriptor(const SamplerDescriptor &sampler) = 0; + virtual void updateSamplerDescriptor(const SamplerDescriptor &sampler, int index = 0) = 0; /** * Read a block of pixels from the drawable texture @@ -78,7 +78,7 @@ public: * Update texture description. * @param descriptor Specifies texture and sampler descriptor. */ - virtual void updateTextureDescriptor(const TextureDescriptor& descriptor); + virtual void updateTextureDescriptor(const TextureDescriptor& descriptor, int index = 0); /** * Get texture format. @@ -104,6 +104,8 @@ public: */ inline bool hasMipmaps() const { return _hasMipmaps; } + virtual int getCount() const = 0; + protected: /** * @param descriptor Specifies the texture descirptor. @@ -136,7 +138,7 @@ public: * @param height Specifies the height of the texture image. * @param level Specifies the level-of-detail number. Level 0 is the base image level. Level n is the nth mipmap reduction image. */ - virtual void updateData(uint8_t* data, std::size_t width , std::size_t height, std::size_t level) = 0; + virtual void updateData(uint8_t* data, std::size_t width , std::size_t height, std::size_t level, int index = 0) = 0; /** * Update a two-dimensional texture image in a compressed format @@ -157,7 +159,7 @@ public: * @param level Specifies the level-of-detail number. Level 0 is the base image level. Level n is the nth mipmap reduction image. * @param data Specifies a pointer to the image data in memory. */ - virtual void updateSubData(std::size_t xoffset, std::size_t yoffset, std::size_t width, std::size_t height, std::size_t level, uint8_t* data) = 0; + virtual void updateSubData(std::size_t xoffset, std::size_t yoffset, std::size_t width, std::size_t height, std::size_t level, uint8_t* data, int index = 0) = 0; /** * Update a two-dimensional texture subimage in a compressed format diff --git a/cocos/renderer/backend/opengl/TextureGL.cpp b/cocos/renderer/backend/opengl/TextureGL.cpp index 0aef8a4808..73706b1fb9 100644 --- a/cocos/renderer/backend/opengl/TextureGL.cpp +++ b/cocos/renderer/backend/opengl/TextureGL.cpp @@ -77,14 +77,14 @@ void TextureInfoGL::applySamplerDescriptor(const SamplerDescriptor& descriptor, Texture2DGL::Texture2DGL(const TextureDescriptor& descriptor) : Texture2DBackend(descriptor) { - glGenTextures(1, &_textureInfo.texture); + glGenTextures(1, &_textureInfo.textures[0]); updateTextureDescriptor(descriptor); #if CC_ENABLE_CACHE_TEXTURE_DATA // Listen this event to restored texture id after coming to foreground on Android. _backToForegroundListener = EventListenerCustom::create(EVENT_RENDERER_RECREATED, [this](EventCustom*){ - glGenTextures(1, &(this->_textureInfo.texture)); + glGenTextures(1, &(this->_textureInfo.textures[0])); this->initWithZeros(); }); Director::getInstance()->getEventDispatcher()->addEventListenerWithFixedPriority(_backToForegroundListener, -1); @@ -100,9 +100,9 @@ void Texture2DGL::initWithZeros() free(data); } -void Texture2DGL::updateTextureDescriptor(const cocos2d::backend::TextureDescriptor &descriptor) +void Texture2DGL::updateTextureDescriptor(const cocos2d::backend::TextureDescriptor &descriptor, int index) { - TextureBackend::updateTextureDescriptor(descriptor); + TextureBackend::updateTextureDescriptor(descriptor, index); UtilsGL::toGLTypes(descriptor.textureFormat, _textureInfo.internalFormat, _textureInfo.format, _textureInfo.type, _isCompressed); bool isPow2 = ISPOW2(_width) && ISPOW2(_height); @@ -112,7 +112,7 @@ void Texture2DGL::updateTextureDescriptor(const cocos2d::backend::TextureDescrip _textureInfo.sAddressModeGL = UtilsGL::toGLAddressMode(descriptor.samplerDescriptor.sAddressMode, isPow2); _textureInfo.tAddressModeGL = UtilsGL::toGLAddressMode(descriptor.samplerDescriptor.tAddressMode, isPow2); - updateSamplerDescriptor(descriptor.samplerDescriptor); + updateSamplerDescriptor(descriptor.samplerDescriptor, index); // Update data here because `updateData()` may not be invoked later. // For example, a texture used as depth buffer will not invoke updateData(). @@ -121,20 +121,18 @@ void Texture2DGL::updateTextureDescriptor(const cocos2d::backend::TextureDescrip Texture2DGL::~Texture2DGL() { - if (_textureInfo.texture) - glDeleteTextures(1, &_textureInfo.texture); - _textureInfo.texture = 0; + _textureInfo.foreach([=](GLuint texID, int) { glDeleteTextures(1, &texID); }); + _textureInfo.textures.fill(0); #if CC_ENABLE_CACHE_TEXTURE_DATA Director::getInstance()->getEventDispatcher()->removeEventListener(_backToForegroundListener); #endif } -void Texture2DGL::updateSamplerDescriptor(const SamplerDescriptor &sampler) { +void Texture2DGL::updateSamplerDescriptor(const SamplerDescriptor &sampler, int index) { bool isPow2 = ISPOW2(_width) && ISPOW2(_height); _textureInfo.applySamplerDescriptor(sampler, isPow2, _hasMipmaps); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, _textureInfo.texture); + ensure(index); if (sampler.magFilter != SamplerFilter::DONT_CARE) { @@ -157,7 +155,7 @@ void Texture2DGL::updateSamplerDescriptor(const SamplerDescriptor &sampler) { } } -void Texture2DGL::updateData(uint8_t* data, std::size_t width , std::size_t height, std::size_t level) +void Texture2DGL::updateData(uint8_t* data, std::size_t width , std::size_t height, std::size_t level, int index) { //Set the row align only when mipmapsNum == 1 and the data is uncompressed auto mipmapEnalbed = isMipmapEnabled(_textureInfo.minFilterGL) || isMipmapEnabled(_textureInfo.magFilterGL); @@ -187,8 +185,8 @@ void Texture2DGL::updateData(uint8_t* data, std::size_t width , std::size_t heig glPixelStorei(GL_UNPACK_ALIGNMENT, 1); } - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, _textureInfo.texture); + auto texID = ensure(index); + if (!texID) return; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, _textureInfo.magFilterGL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, _textureInfo.minFilterGL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, _textureInfo.sAddressModeGL); @@ -204,6 +202,9 @@ void Texture2DGL::updateData(uint8_t* data, std::size_t width , std::size_t heig _textureInfo.format, _textureInfo.type, data); + + cocos2d::log("---> Texture2DGL::updateData:%u", texID); + CHECK_GL_ERROR_DEBUG(); if(!_hasMipmaps && level > 0) @@ -216,7 +217,7 @@ void Texture2DGL::updateCompressedData(uint8_t *data, std::size_t width, std::si glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, _textureInfo.texture); + glBindTexture(GL_TEXTURE_2D, _textureInfo.textures[0]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, _textureInfo.magFilterGL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, _textureInfo.minFilterGL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, _textureInfo.sAddressModeGL); @@ -237,10 +238,9 @@ void Texture2DGL::updateCompressedData(uint8_t *data, std::size_t width, std::si _hasMipmaps = true; } -void Texture2DGL::updateSubData(std::size_t xoffset, std::size_t yoffset, std::size_t width, std::size_t height, std::size_t level, uint8_t* data) +void Texture2DGL::updateSubData(std::size_t xoffset, std::size_t yoffset, std::size_t width, std::size_t height, std::size_t level, uint8_t* data, int index) { - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, _textureInfo.texture); + if (!ensure(index)) return; glTexSubImage2D(GL_TEXTURE_2D, level, @@ -262,7 +262,7 @@ void Texture2DGL::updateCompressedSubData(std::size_t xoffset, std::size_t yoffs uint8_t *data) { glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, _textureInfo.texture); + glBindTexture(GL_TEXTURE_2D, _textureInfo.textures[0]); glCompressedTexSubImage2D(GL_TEXTURE_2D, level, @@ -282,7 +282,21 @@ void Texture2DGL::updateCompressedSubData(std::size_t xoffset, std::size_t yoffs void Texture2DGL::apply(int index) const { glActiveTexture(GL_TEXTURE0 + index); - glBindTexture(GL_TEXTURE_2D, _textureInfo.texture); + glBindTexture(GL_TEXTURE_2D, index < CC_META_TEXTURES ? _textureInfo.textures[index] : 0); +} + +GLuint Texture2DGL::ensure(int index) +{ + if (index >= CC_META_TEXTURES) return 0; + glActiveTexture(GL_TEXTURE0 + index); + auto& texID = _textureInfo.textures[index]; + if (!texID) + glGenTextures(1, &texID); + glBindTexture(GL_TEXTURE_2D, texID); + + if (_maxTextureIndex < index) _maxTextureIndex = index; + + return texID; } void Texture2DGL::generateMipmaps() @@ -293,7 +307,7 @@ void Texture2DGL::generateMipmaps() if(!_hasMipmaps) { _hasMipmaps = true; - glBindTexture(GL_TEXTURE_2D, _textureInfo.texture); + glBindTexture(GL_TEXTURE_2D, _textureInfo.textures[0]); glGenerateMipmap(GL_TEXTURE_2D); } } @@ -306,7 +320,7 @@ void Texture2DGL::getBytes(std::size_t x, std::size_t y, std::size_t width, std: GLuint frameBuffer = 0; glGenFramebuffers(1, &frameBuffer); glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _textureInfo.texture, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _textureInfo.textures[0], 0); glPixelStorei(GL_PACK_ALIGNMENT, 1); auto bytePerRow = width * _bitsPerElement / 8; @@ -340,7 +354,7 @@ TextureCubeGL::TextureCubeGL(const TextureDescriptor& descriptor) assert(_width == _height); _textureType = TextureType::TEXTURE_CUBE; UtilsGL::toGLTypes(_textureFormat, _textureInfo.internalFormat, _textureInfo.format, _textureInfo.type, _isCompressed); - glGenTextures(1, &_textureInfo.texture); + glGenTextures(1, &_textureInfo.textures[0]); updateSamplerDescriptor(descriptor.samplerDescriptor); #if CC_ENABLE_CACHE_TEXTURE_DATA @@ -357,7 +371,7 @@ TextureCubeGL::TextureCubeGL(const TextureDescriptor& descriptor) void TextureCubeGL::setTexParameters() { glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_CUBE_MAP, _textureInfo.texture); + glBindTexture(GL_TEXTURE_CUBE_MAP, _textureInfo.textures[0]); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, _textureInfo.minFilterGL); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, _textureInfo.magFilterGL); @@ -367,41 +381,40 @@ void TextureCubeGL::setTexParameters() glBindTexture(GL_TEXTURE_CUBE_MAP, 0); } -void TextureCubeGL::updateTextureDescriptor(const cocos2d::backend::TextureDescriptor &descriptor) +void TextureCubeGL::updateTextureDescriptor(const cocos2d::backend::TextureDescriptor &descriptor, int index) { UtilsGL::toGLTypes(descriptor.textureFormat, _textureInfo.internalFormat, _textureInfo.format, _textureInfo.type, _isCompressed); _textureFormat = descriptor.textureFormat; - updateSamplerDescriptor(descriptor.samplerDescriptor); + updateSamplerDescriptor(descriptor.samplerDescriptor, index); } TextureCubeGL::~TextureCubeGL() { - if(_textureInfo.texture) - glDeleteTextures(1, &_textureInfo.texture); - _textureInfo.texture = 0; + _textureInfo.foreach([=](GLuint texID, int) { glDeleteTextures(1, &texID); }); + _textureInfo.textures.fill(0); #if CC_ENABLE_CACHE_TEXTURE_DATA Director::getInstance()->getEventDispatcher()->removeEventListener(_backToForegroundListener); #endif } -void TextureCubeGL::updateSamplerDescriptor(const SamplerDescriptor &sampler) +void TextureCubeGL::updateSamplerDescriptor(const SamplerDescriptor &sampler, int /*index*/) { _textureInfo.applySamplerDescriptor(sampler, true, _hasMipmaps); setTexParameters(); } -void TextureCubeGL::apply(int index) const +void TextureCubeGL::apply(int location) const { - glActiveTexture(GL_TEXTURE0+ index); - glBindTexture(GL_TEXTURE_CUBE_MAP, _textureInfo.texture); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_CUBE_MAP, _textureInfo.textures[0]); CHECK_GL_ERROR_DEBUG(); } void TextureCubeGL::updateFaceData(TextureCubeFace side, void *data) { glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_CUBE_MAP, _textureInfo.texture); + glBindTexture(GL_TEXTURE_CUBE_MAP, _textureInfo.textures[0]); CHECK_GL_ERROR_DEBUG(); int i = static_cast(side); glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, @@ -425,7 +438,7 @@ void TextureCubeGL::getBytes(std::size_t x, std::size_t y, std::size_t width, st GLuint frameBuffer = 0; glGenFramebuffers(1, &frameBuffer); glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP, _textureInfo.texture, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP, _textureInfo.textures[0], 0); glPixelStorei(GL_PACK_ALIGNMENT, 1); auto bytePerRow = width * _bitsPerElement / 8; @@ -461,7 +474,7 @@ void TextureCubeGL::generateMipmaps() if(!_hasMipmaps) { _hasMipmaps = true; - glBindTexture(GL_TEXTURE_CUBE_MAP, _textureInfo.texture); + glBindTexture(GL_TEXTURE_CUBE_MAP, _textureInfo.textures[0]); glGenerateMipmap(GL_TEXTURE_CUBE_MAP); } } diff --git a/cocos/renderer/backend/opengl/TextureGL.h b/cocos/renderer/backend/opengl/TextureGL.h index 98fc93a0ac..3e65cd723a 100644 --- a/cocos/renderer/backend/opengl/TextureGL.h +++ b/cocos/renderer/backend/opengl/TextureGL.h @@ -24,6 +24,7 @@ #pragma once +#include #include "../Texture.h" #include "platform/CCGL.h" #include "base/CCEventListenerCustom.h" @@ -36,6 +37,17 @@ CC_BACKEND_BEGIN struct TextureInfoGL { void applySamplerDescriptor(const SamplerDescriptor &desc, bool isPow2, bool hasMipmaps); + TextureInfoGL() { + textures.fill(0); + } + + template + void foreach(const _Fty& cb) const { + GLuint texID; + int idx = 0; + while (texID = textures[idx]) + cb(texID, idx++); + } GLint magFilterGL = GL_LINEAR; GLint minFilterGL = GL_LINEAR; @@ -47,7 +59,7 @@ struct TextureInfoGL GLenum format = GL_RGBA; GLenum type = GL_UNSIGNED_BYTE; - GLuint texture = 0; + std::array textures; }; /** @@ -74,7 +86,7 @@ public: * @param height Specifies the height of the texture image. * @param level Specifies the level-of-detail number. Level 0 is the base image level. Level n is the nth mipmap reduction image. */ - virtual void updateData(uint8_t* data, std::size_t width , std::size_t height, std::size_t level) override; + virtual void updateData(uint8_t* data, std::size_t width , std::size_t height, std::size_t level, int index = 0) override; /** * Update a two-dimensional texture image in a compressed format @@ -95,7 +107,7 @@ public: * @param level Specifies the level-of-detail number. Level 0 is the base image level. Level n is the nth mipmap reduction image. * @param data Specifies a pointer to the image data in memory. */ - virtual void updateSubData(std::size_t xoffset, std::size_t yoffset, std::size_t width, std::size_t height, std::size_t level, uint8_t* data) override; + virtual void updateSubData(std::size_t xoffset, std::size_t yoffset, std::size_t width, std::size_t height, std::size_t level, uint8_t* data, int index = 0) override; /** * Update a two-dimensional texture subimage in a compressed format @@ -113,7 +125,7 @@ public: * Update sampler * @param sampler Specifies the sampler descriptor. */ - virtual void updateSamplerDescriptor(const SamplerDescriptor &sampler) override; + virtual void updateSamplerDescriptor(const SamplerDescriptor &sampler, int index = 0) override; /** * Read a block of pixels from the drawable texture @@ -133,13 +145,13 @@ public: * Update texture description. * @param descriptor Specifies texture and sampler descriptor. */ - virtual void updateTextureDescriptor(const TextureDescriptor& descriptor) override; + virtual void updateTextureDescriptor(const TextureDescriptor& descriptor, int index = 0) override; /** * Get texture object. * @return Texture object. */ - inline GLuint getHandler() const { return _textureInfo.texture; } + inline GLuint getHandler() const { return _textureInfo.textures[0]; } /** * Set texture to pipeline @@ -147,10 +159,15 @@ public: */ void apply(int index) const; + GLuint ensure(int index); + + int getCount() const override { return _maxTextureIndex + 1; } + private: void initWithZeros(); TextureInfoGL _textureInfo; + int _maxTextureIndex = 0; EventListener* _backToForegroundListener = nullptr; }; @@ -170,7 +187,7 @@ public: * Update sampler * @param sampler Specifies the sampler descriptor. */ - virtual void updateSamplerDescriptor(const SamplerDescriptor &sampler) override; + virtual void updateSamplerDescriptor(const SamplerDescriptor &sampler, int index = 0) override; /** * Update texutre cube data in give slice side. @@ -195,19 +212,21 @@ public: * Update texture description. * @param descriptor Specifies texture and sampler descriptor. */ - virtual void updateTextureDescriptor(const TextureDescriptor& descriptor) override ; + virtual void updateTextureDescriptor(const TextureDescriptor& descriptor, int index = 0) override ; /** * Get texture object. * @return Texture object. */ - inline GLuint getHandler() const { return _textureInfo.texture; } + inline GLuint getHandler() const { return _textureInfo.textures[0]; } /** * Set texture to pipeline * @param index Specifies the texture image unit selector. */ - void apply(int index) const; + void apply(int location) const; + + int getCount() const { return 1; } private: void setTexParameters(); diff --git a/cocos/ui/UIAbstractCheckButton.cpp b/cocos/ui/UIAbstractCheckButton.cpp index 8bd402ab71..d281d0ba7f 100644 --- a/cocos/ui/UIAbstractCheckButton.cpp +++ b/cocos/ui/UIAbstractCheckButton.cpp @@ -27,6 +27,7 @@ THE SOFTWARE. #include "2d/CCSprite.h" #include "editor-support/cocostudio/CocosStudioExtension.h" #include "renderer/ccShaders.h" +#include "renderer/backend/ProgramStateRegistry.h" NS_CC_BEGIN @@ -309,12 +310,8 @@ void AbstractCheckButton::onPressStateChangedToNormal() _backGroundBoxDisabledRenderer->setVisible(false); _frontCrossDisabledRenderer->setVisible(false); - auto isETC1 = _backGroundBoxRenderer->getTexture() && _backGroundBoxRenderer->getTexture()->getAlphaTextureName(); - _backGroundBoxRenderer->updateShaders(positionTextureColor_vert, (isETC1)?etc1_frag:positionTextureColor_frag); - - isETC1 = _frontCrossRenderer->getTexture() && _frontCrossRenderer->getTexture()->getAlphaTextureName(); - _frontCrossRenderer->updateShaders(positionTextureColor_vert, (isETC1)?etc1_frag:positionTextureColor_frag); - + _backGroundBoxRenderer->setProgramState(backend::ProgramType::POSITION_TEXTURE_COLOR); + _frontCrossRenderer->setProgramState(backend::ProgramType::POSITION_TEXTURE_COLOR); _backGroundBoxRenderer->setScale(_backgroundTextureScaleX, _backgroundTextureScaleY); _frontCrossRenderer->setScale(_backgroundTextureScaleX, _backgroundTextureScaleY); @@ -329,11 +326,8 @@ void AbstractCheckButton::onPressStateChangedToNormal() void AbstractCheckButton::onPressStateChangedToPressed() { - auto isETC1 = _backGroundBoxRenderer->getTexture() && _backGroundBoxRenderer->getTexture()->getAlphaTextureName(); - _backGroundBoxRenderer->updateShaders(positionTextureColor_vert, (isETC1)?etc1_frag:positionTextureColor_frag); - - isETC1 = _frontCrossRenderer->getTexture() && _frontCrossRenderer->getTexture()->getAlphaTextureName(); - _frontCrossRenderer->updateShaders(positionTextureColor_vert, (isETC1)?etc1_frag:positionTextureColor_frag); + _backGroundBoxRenderer->setProgramState(backend::ProgramType::POSITION_TEXTURE_COLOR); + _frontCrossRenderer->setProgramState(backend::ProgramType::POSITION_TEXTURE_COLOR); if (!_isBackgroundSelectedTextureLoaded) { @@ -356,11 +350,9 @@ void AbstractCheckButton::onPressStateChangedToDisabled() if (!_isBackgroundDisabledTextureLoaded || !_isFrontCrossDisabledTextureLoaded) { - auto isETC1 = _backGroundBoxRenderer->getTexture() && _backGroundBoxRenderer->getTexture()->getAlphaTextureName(); - _backGroundBoxRenderer->updateShaders(positionTextureColor_vert, (isETC1)?etc1Gray_frag:grayScale_frag); + _backGroundBoxRenderer->setProgramState(backend::ProgramType::GRAY_SCALE); - isETC1 = _frontCrossRenderer->getTexture() && _frontCrossRenderer->getTexture()->getAlphaTextureName(); - _frontCrossRenderer->updateShaders(positionTextureColor_vert, (isETC1)?etc1Gray_frag:grayScale_frag); + _frontCrossRenderer->setProgramState(backend::ProgramType::GRAY_SCALE); } else { diff --git a/cocos/ui/UIScale9Sprite.cpp b/cocos/ui/UIScale9Sprite.cpp index 53970b99ec..a256098c71 100644 --- a/cocos/ui/UIScale9Sprite.cpp +++ b/cocos/ui/UIScale9Sprite.cpp @@ -35,6 +35,7 @@ #include "2d/CCDrawNode.h" #include "2d/CCCamera.h" #include "renderer/CCRenderer.h" +#include "renderer/backend/ProgramStateRegistry.h" using namespace cocos2d; using namespace cocos2d::ui; @@ -304,14 +305,13 @@ void Scale9Sprite::setState(Scale9Sprite::State state) { if (_brightState != state) { _brightState = state; - auto isETC1 = getTexture() && getTexture()->getAlphaTextureName(); switch (state) { case State::NORMAL: - Sprite::updateShaders(positionTextureColor_vert, (isETC1)?etc1_frag:positionTextureColor_frag); + Sprite::setProgramState(backend::ProgramType::POSITION_TEXTURE_COLOR); break; case State::GRAY: - Sprite::updateShaders(positionTextureColor_vert, (isETC1)?etc1Gray_frag:grayScale_frag); + Sprite::setProgramState(backend::ProgramType::GRAY_SCALE); default: break; } diff --git a/cocos/ui/UISlider.cpp b/cocos/ui/UISlider.cpp index 8c6669e9a1..700966643b 100644 --- a/cocos/ui/UISlider.cpp +++ b/cocos/ui/UISlider.cpp @@ -680,15 +680,13 @@ void Slider::onPressStateChangedToNormal() _slidBallPressedRenderer->setVisible(false); _slidBallDisabledRenderer->setVisible(false); - auto isETC1 = _slidBallNormalRenderer->getTexture() && _slidBallNormalRenderer->getTexture()->getAlphaTextureName(); - _slidBallNormalRenderer->updateShaders(positionTextureColor_vert, (isETC1)?etc1_frag:positionTextureColor_frag); + _slidBallNormalRenderer->setProgramState(backend::ProgramType::POSITION_TEXTURE_COLOR); _slidBallNormalRenderer->setScale(_sliderBallNormalTextureScaleX, _sliderBallNormalTextureScaleY); } void Slider::onPressStateChangedToPressed() { - auto isETC1 = _slidBallNormalRenderer->getTexture() && _slidBallNormalRenderer->getTexture()->getAlphaTextureName(); - _slidBallNormalRenderer->updateShaders(positionTextureColor_vert, (isETC1)?etc1_frag:positionTextureColor_frag); + _slidBallNormalRenderer->setProgramState(backend::ProgramType::POSITION_TEXTURE_COLOR); if (!_isSliderBallPressedTextureLoaded) { @@ -707,8 +705,7 @@ void Slider::onPressStateChangedToDisabled() { if (!_isSliderBallDisabledTexturedLoaded) { - auto isETC1 = _slidBallNormalRenderer->getTexture() && _slidBallNormalRenderer->getTexture()->getAlphaTextureName(); - _slidBallNormalRenderer->updateShaders(positionTextureColor_vert, (isETC1)?etc1Gray_frag:grayScale_frag); + _slidBallNormalRenderer->setProgramState(backend::ProgramType::GRAY_SCALE); _slidBallNormalRenderer->setVisible(true); } else