How DrawNode::drawDot works?

Hi!

Quick question: how DrawNode::drawDot is able to draw a perfect circle if only two triangles are employed to draw the dot?

Thanks!

void DrawNode::drawDot(const Point &pos, float radius, const Color4F &color)
{
    unsigned int vertex_count = 2*3;
    ensureCapacity(vertex_count);
	
	V2F_C4B_T2F a = {Vertex2F(pos.x - radius, pos.y - radius), Color4B(color), Tex2F(-1.0, -1.0) };
	V2F_C4B_T2F b = {Vertex2F(pos.x - radius, pos.y + radius), Color4B(color), Tex2F(-1.0,  1.0) };
	V2F_C4B_T2F c = {Vertex2F(pos.x + radius, pos.y + radius), Color4B(color), Tex2F( 1.0,  1.0) };
	V2F_C4B_T2F d = {Vertex2F(pos.x + radius, pos.y - radius), Color4B(color), Tex2F( 1.0, -1.0) };
	
	V2F_C4B_T2F_Triangle *triangles = (V2F_C4B_T2F_Triangle *)(_buffer + _bufferCount);
    V2F_C4B_T2F_Triangle triangle0 = {a, b, c};
    V2F_C4B_T2F_Triangle triangle1 = {a, c, d};
	triangles[0] = triangle0;
	triangles[1] = triangle1;
	
	_bufferCount += vertex_count;
	
	_dirty = true;
}

The answer is in the shader being used to draw those triangles.

Thanks!

I supposed the magic was in the shader, but I was not sure.

The weird thing is that it seems that DrawNode is using the same shader for all the shapes (dot, polygon, etc), so I think that for other shapes a lot of performance can be gained by setting the “basic” or “default” shader instead of the current one.

Do you know how to set the basic shader to DrawNode?

bool DrawNode::init()
{
    _blendFunc = BlendFunc::ALPHA_PREMULTIPLIED;

    setShaderProgram(ShaderCache::getInstance()->getProgram(GLProgram::SHADER_NAME_POSITION_LENGTH_TEXTURE_COLOR));

    ...
}

You can’t set a separate shader for polygons and other primitives. DrawNode is being drawn with one draw call, it means that all the primitives are being drawn with that single draw call, thus it’s necessary to use a common shader (you can’t use more than one shader during one draw call).
Actually, the overhead is not so big. I’m pretty sure that if you separate DrawNode into two parts: dot and other primitives, you’ll have a purer performance because of two draw calls.
Moreover, premature optimization is the root of all evil.

dotsquid wrote:

You can’t set a separate shader for polygons and other primitives. DrawNode is being drawn with one draw call, it means that all the primitives are being drawn with that single draw call, thus it’s necessary to use a common shader (you can’t use more than one shader during one draw call).
Actually, the overhead is not so big. I’m pretty sure that if you separate DrawNode into two parts: dot and other primitives, you’ll have a purer performance because of two draw calls.

I know that you can’t set more than one shader per node.
What i’m doing is learning how DrawNode works to create a lighter, faster version of it.
With this new node I only want to draw raw polygons (not rounded ones), so I think it would be beneficial for this new node to have a basic shader instead of the DrawNode one.

So…
Do you know which is the most simple shader available in cocos2d-x?

I suppose it should be one of these:

static const char * 	SHADER_NAME_POSITION_TEXTURE_COLOR
static const char * 	SHADER_NAME_POSITION_TEXTURE_COLOR_NO_MVP
static const char * 	SHADER_NAME_POSITION_TEXTURE_ALPHA_TEST
static const char * 	SHADER_NAME_POSITION_COLOR
static const char * 	SHADER_NAME_POSITION_COLOR_NO_MVP
static const char * 	SHADER_NAME_POSITION_TEXTURE
static const char * 	SHADER_NAME_POSITION_TEXTURE_U_COLOR
static const char * 	SHADER_NAME_POSITION_TEXTURE_A8_COLOR
static const char * 	SHADER_NAME_POSITION_U_COLOR
static const char * 	SHADER_NAME_POSITION_LENGTH_TEXTURE_COLOR
static const char * 	SHADER_NAME_LABEL_DISTANCEFIELD_NORMAL
static const char * 	SHADER_NAME_LABEL_DISTANCEFIELD_GLOW
static const char * 	SHADER_NAME_LABEL_DISTANCEFIELD_OUTLINE
static const char * 	SHADER_NAME_LABEL_DISTANCEFIELD_SHADOW

dotsquid wrote:

Moreover, premature optimization is the root of all evil.

Yeah I know. But it’s so fun! :slight_smile:

It depends on the requirements to your implementation of DrawNode. Probably you don’t need a texture (currently it’s being used for drawing smooth circles). So I guess POSITION_COLOR will fit your needs.

So weird! :;qst

Dots drawing performance with POSITION_COLOR is the same than drawing with the DrawNode shader.
It seems CPU limited because CPU core usage is at 100%, although most of the time is spent on EGLView::swapBuffers().

This is the test code:

auto draw = DrawNode::create();
addChild(draw, 10);

for(int index = 0, limit = 1000; index < limit; index++)
{
	// Draw 10 circles
	for( int i=0; i < 10; i++)
	{
		draw->drawDot(Point(s.width/2, s.height/2), 10*(10-i), Color4F(CCRANDOM_0_1(), CCRANDOM_0_1(), CCRANDOM_0_1(), 1));
	}
}

By the way, on my PC (with a Radeon HD 5850) this test runs at 23fps.
Is this normal?

Are you recreating a DrawNode each frame? AFAIK DrawNode is not designed for this http://www.cocos2d-x.org/forums/6/topics/39305

Nope, it’s created in the constructor, like in DrawPrimitivesTest.cpp
http://github.com/cocos2d/cocos2d-x/blob/develop/tests/test-cpp/Classes/DrawPrimitivesTest/DrawPrimitivesTest.cpp

Well, maybe you’ve got low performance because of high overdraw, since dots are using alpha blending and you draw a lot of overlapping dots.

That is! :slight_smile:

Disabling blending and using the basic shader the fps goes from 23 to 36.
I think a custom node can be useful for drawing basic polygons.

Thanks!