fix: TriangleCommands with custom uniforms can be batched (#16329)

* fix: TriangleCommands with custom uniforms can be batched

TriangleCommands with custom uniforms can be batched together.

This improves the performance when using custom uniforms without
adding any penalties when not using them

Github issue #16224

* better tests
This commit is contained in:
Ricardo Quesada 2016-08-07 14:51:02 -07:00 committed by GitHub
parent 0e65025bda
commit f7464f8de5
4 changed files with 210 additions and 19 deletions

View File

@ -36,7 +36,6 @@ TrianglesCommand::TrianglesCommand()
:_materialID(0)
,_textureID(0)
,_glProgramState(nullptr)
,_glProgram(nullptr)
,_blendType(BlendFunc::DISABLE)
,_alphaTextureID(0)
{
@ -60,13 +59,11 @@ void TrianglesCommand::init(float globalOrder, GLuint textureID, GLProgramState*
_mv = mv;
if( _textureID != textureID || _blendType.src != blendType.src || _blendType.dst != blendType.dst ||
_glProgramState != glProgramState ||
_glProgram != glProgramState->getGLProgram())
_glProgramState != glProgramState)
{
_textureID = textureID;
_blendType = blendType;
_glProgramState = glProgramState;
_glProgram = glProgramState->getGLProgram();
generateMaterialID();
}
@ -89,18 +86,25 @@ TrianglesCommand::~TrianglesCommand()
void TrianglesCommand::generateMaterialID()
{
// do not batch if using custom uniforms (since we cannot batch) it
if(_glProgramState->getUniformCount() > 0)
{
_materialID = Renderer::MATERIAL_ID_DO_NOT_BATCH;
setSkipBatching(true);
}
else
{
int glProgram = (int)_glProgram->getProgram();
int intArray[4] = { glProgram, (int)_textureID, (int)_blendType.src, (int)_blendType.dst};
_materialID = XXH32((const void*)intArray, sizeof(intArray), 0);
}
// glProgramState is hashed because it contains:
// * uniforms/values
// * glProgram
//
// we safely can when the same glProgramState is being used then they share those states
// if they don't have the same glProgramState, they might still have the same
// uniforms/values and glProgram, but it would be too expensive to check the uniforms.
struct {
GLuint textureId;
GLenum blendSrc;
GLenum blendDst;
void* glProgramState;
} hashMe;
hashMe.textureId = _textureID;
hashMe.blendSrc = _blendType.src;
hashMe.blendDst = _blendType.dst;
hashMe.glProgramState = _glProgramState;
_materialID = XXH32((const void*)&hashMe, sizeof(hashMe), 0);
}
void TrianglesCommand::useMaterial() const

View File

@ -105,8 +105,6 @@ protected:
GLuint _textureID;
/**GLprogramstate for the command. encapsulate shaders and uniforms.*/
GLProgramState* _glProgramState;
/**The GLProgram used by GLProgramState*/
GLProgram* _glProgram;
/**Blend function when rendering the triangles.*/
BlendFunc _blendType;
/**Rendered triangles.*/

View File

@ -38,6 +38,8 @@ NewRendererTests::NewRendererTests()
ADD_TEST_CASE(CaptureNodeTest);
ADD_TEST_CASE(BugAutoCulling);
ADD_TEST_CASE(RendererBatchQuadTri);
ADD_TEST_CASE(RendererUniformBatch);
ADD_TEST_CASE(RendererUniformBatch2);
};
std::string MultiSceneTest::title() const
@ -610,3 +612,164 @@ std::string RendererBatchQuadTri::subtitle() const
{
return "QuadCommand and TriangleCommands are batched together";
}
//
//
// RendererUniformBatch
//
RendererUniformBatch::RendererUniformBatch()
{
Size s = Director::getInstance()->getWinSize();
auto glBlurState = createBlurGLProgramState();
auto glSepiaState = createSepiaGLProgramState();
auto x_inc = s.width / 20;
auto y_inc = s.height / 6;
for (int y=0; y<6; ++y)
{
for (int x=0; x<20; ++x)
{
auto sprite = Sprite::create("Images/grossini.png");
sprite->setPosition(Vec2(x * x_inc, y * y_inc));
sprite->setScale(0.4);
addChild(sprite);
if (y>=4) {
sprite->setGLProgramState(glSepiaState);
} else if(y>=2) {
sprite->setGLProgramState(glBlurState);
}
}
}
}
GLProgramState* RendererUniformBatch::createBlurGLProgramState()
{
#if (CC_TARGET_PLATFORM != CC_PLATFORM_WINRT)
const std::string shaderName("Shaders/example_Blur.fsh");
#else
const std::string shaderName("Shaders/example_Blur_winrt.fsh");
#endif
// outline shader
auto fileUtiles = FileUtils::getInstance();
auto fragmentFullPath = fileUtiles->fullPathForFilename(shaderName);
auto fragSource = fileUtiles->getStringFromFile(fragmentFullPath);
auto glprogram = GLProgram::createWithByteArrays(ccPositionTextureColor_noMVP_vert, fragSource.c_str());
auto glprogramstate = (glprogram == nullptr ? nullptr : GLProgramState::getOrCreateWithGLProgram(glprogram));
glprogramstate->setUniformVec2("resolution", Vec2(85,121));
#if (CC_TARGET_PLATFORM != CC_PLATFORM_WINRT)
glprogramstate->setUniformFloat("blurRadius", 10);
glprogramstate->setUniformFloat("sampleNum", 5);
#endif
return glprogramstate;
}
GLProgramState* RendererUniformBatch::createSepiaGLProgramState()
{
const std::string shaderName("Shaders/example_Sepia.fsh");
// outline shader
auto fileUtiles = FileUtils::getInstance();
auto fragmentFullPath = fileUtiles->fullPathForFilename(shaderName);
auto fragSource = fileUtiles->getStringFromFile(fragmentFullPath);
auto glprogram = GLProgram::createWithByteArrays(ccPositionTextureColor_noMVP_vert, fragSource.c_str());
auto glprogramstate = (glprogram == nullptr ? nullptr : GLProgramState::getOrCreateWithGLProgram(glprogram));
return glprogramstate;
}
std::string RendererUniformBatch::title() const
{
return "RendererUniformBatch";
}
std::string RendererUniformBatch::subtitle() const
{
return "Only 9 draw calls should appear";
}
//
// RendererUniformBatch2
//
RendererUniformBatch2::RendererUniformBatch2()
{
Size s = Director::getInstance()->getWinSize();
auto glBlurState = createBlurGLProgramState();
auto glSepiaState = createSepiaGLProgramState();
auto x_inc = s.width / 20;
auto y_inc = s.height / 6;
for (int y=0; y<6; ++y)
{
for (int x=0; x<20; ++x)
{
auto sprite = Sprite::create("Images/grossini.png");
sprite->setPosition(Vec2(x * x_inc, y * y_inc));
sprite->setScale(0.4);
addChild(sprite);
auto r = CCRANDOM_0_1();
if (r < 0.33)
sprite->setGLProgramState(glSepiaState);
else if (r < 0.66)
sprite->setGLProgramState(glBlurState);
}
}
}
GLProgramState* RendererUniformBatch2::createBlurGLProgramState()
{
#if (CC_TARGET_PLATFORM != CC_PLATFORM_WINRT)
const std::string shaderName("Shaders/example_Blur.fsh");
#else
const std::string shaderName("Shaders/example_Blur_winrt.fsh");
#endif
// outline shader
auto fileUtiles = FileUtils::getInstance();
auto fragmentFullPath = fileUtiles->fullPathForFilename(shaderName);
auto fragSource = fileUtiles->getStringFromFile(fragmentFullPath);
auto glprogram = GLProgram::createWithByteArrays(ccPositionTextureColor_noMVP_vert, fragSource.c_str());
auto glprogramstate = (glprogram == nullptr ? nullptr : GLProgramState::getOrCreateWithGLProgram(glprogram));
glprogramstate->setUniformVec2("resolution", Vec2(85,121));
#if (CC_TARGET_PLATFORM != CC_PLATFORM_WINRT)
glprogramstate->setUniformFloat("blurRadius", 10);
glprogramstate->setUniformFloat("sampleNum", 5);
#endif
return glprogramstate;
}
GLProgramState* RendererUniformBatch2::createSepiaGLProgramState()
{
const std::string shaderName("Shaders/example_Sepia.fsh");
// outline shader
auto fileUtiles = FileUtils::getInstance();
auto fragmentFullPath = fileUtiles->fullPathForFilename(shaderName);
auto fragSource = fileUtiles->getStringFromFile(fragmentFullPath);
auto glprogram = GLProgram::createWithByteArrays(ccPositionTextureColor_noMVP_vert, fragSource.c_str());
auto glprogramstate = (glprogram == nullptr ? nullptr : GLProgramState::getOrCreateWithGLProgram(glprogram));
return glprogramstate;
}
std::string RendererUniformBatch2::title() const
{
return "RendererUniformBatch 2";
}
std::string RendererUniformBatch2::subtitle() const
{
return "Mixing different shader states should work ok";
}

View File

@ -166,4 +166,30 @@ protected:
RendererBatchQuadTri();
};
class RendererUniformBatch : public MultiSceneTest
{
public:
CREATE_FUNC(RendererUniformBatch);
virtual std::string title() const override;
virtual std::string subtitle() const override;
protected:
RendererUniformBatch();
cocos2d::GLProgramState* createBlurGLProgramState();
cocos2d::GLProgramState* createSepiaGLProgramState();
};
class RendererUniformBatch2 : public MultiSceneTest
{
public:
CREATE_FUNC(RendererUniformBatch2);
virtual std::string title() const override;
virtual std::string subtitle() const override;
protected:
RendererUniformBatch2();
cocos2d::GLProgramState* createBlurGLProgramState();
cocos2d::GLProgramState* createSepiaGLProgramState();
};
#endif //__NewRendererTest_H_