Metal support alpha1 released

Compared to alpha0, this version finished:

  • support all 3d features
    • Sprite3D
    • Particle3D
    • NavMesh
    • Physics3D
    • Billboard
    • MotionStreak3d
    • DrawNode3d
    • Terrain
  • support spine but is not merged because the license, the PR sent to Spine runtime is here
  • enable physics
  • support capture screen and capture node
  • rendertexture can save to images
  • enable all cpp test cases
  • fix many bugs

Download

metal-support-alpha1.zip.

How to run

  • mac: use cocos command or CMake
  • iOS: use CMake to generate Xcode project, then run
  • Android: use cocos command or Android Studio
  • windows: use cocos command or CMake
  • linux: it is not tested yet

CMake usage can refer to cmake/README.md.

Next plan

  • fixing bugs
  • supporting lua

Known issues

  • lua is not completed supported
  • JS project is not supported
  • other known issues are here.
6 Likes

Awesome!

What’s the deal with spine license?

Can not modify any codes. You can refer to license/LICENSE_spine.text for detail information.

I guess it’s impossible to use it with metal without modifying? Maybe you could contact with Spine creator and get a permission?

From the other hand, as far as I remember, spine runtimes in current cocos2d-x are also slightly modified.

We have already sent a PR to official repo, and the author knows it.

In my own code base I’ve disabled the Spine module included in Cocos2d-x, and I’ve been using the one from the official EsotericSoftware github repo (spine-cpp runtime), and that works perfectly fine. It doesn’t seem like there is anything special about the one included with Cocos2d-x, besides not being the latest version with bug-fixes.

@zhangxm I would love to test this alpha release, but the only way that can happen is if I get access to the compatible Spine release, since my game relies on it.

@R101 thanks. About spine runtime, you can take a look of the PR sent to Spine official repo.

Thanks for that. I’ll merge the changes from the PR into my local Spine code and will do some tests with this new alpha release.

I’m getting these warnings in the console window while running the Win32 build:

warning: vertex attribute 'a_texCoord' already set
warning: vertex attribute 'a_color' already set
warning: vertex attribute 'a_position' already set
warning: vertex attribute 'a_texCoord' already set
warning: vertex attribute 'a_color' already set
warning: vertex attribute 'a_position' already set
warning: vertex attribute 'a_texCoord' already set
warning: vertex attribute 'a_color' already set
warning: vertex attribute 'a_position' already set

... over and over again ...

From here:

void VertexLayout::setAtrribute(const std::string &name, unsigned int index, VertexFormat format, unsigned int offset, bool needToBeNormallized)
{
    if (_attributes.find(name) != _attributes.end())
    {
        CCLOG("warning: vertex attribute '%s' already set", name.c_str());
    }
    _attributes[name] = { name, index, format, offset, needToBeNormallized };
}

Which called by this:

void Label::setVertexLayout(PipelineDescriptor& pipelineDescriptor)
{
    auto& layout = pipelineDescriptor.vertexLayout;
    const auto& attributeInfo = _programState->getProgram()->getActiveAttributes();
    auto iter = attributeInfo.find("a_position");
    if(iter != attributeInfo.end())
    {
        layout.setAtrribute("a_position", iter->second.location, backend::VertexFormat::FLOAT3, 0, false);
    }
    iter = attributeInfo.find("a_texCoord");
    if(iter != attributeInfo.end())
    {
        layout.setAtrribute("a_texCoord", iter->second.location, backend::VertexFormat::FLOAT2, offsetof(V3F_C4B_T2F, texCoords), false);
    }
    iter = attributeInfo.find("a_color");
    if(iter != attributeInfo.end())
    {
        layout.setAtrribute("a_color", iter->second.location, backend::VertexFormat::UBYTE4, offsetof(V3F_C4B_T2F, colors), true);
    }
    layout.setLayout(sizeof(V3F_C4B_T2F), backend::VertexStepMode::VERTEX);

}

Here is the callstack:

 	Slots2D.exe!cocos2d::backend::VertexLayout::setAtrribute(const std::basic_string<char,std::char_traits<char>,std::allocator<char> > & name, unsigned int index, cocos2d::backend::VertexFormat format, unsigned int offset, bool needToBeNormallized) Line 11	C++
>	Slots2D.exe!cocos2d::Label::setVertexLayout(cocos2d::PipelineDescriptor & pipelineDescriptor) Line 603	C++
 	Slots2D.exe!cocos2d::Label::updateShaderProgram() Line 717	C++
 	Slots2D.exe!cocos2d::Label::draw(cocos2d::Renderer * renderer, const cocos2d::Mat4 & transform, unsigned int flags) Line 1795	C++
 	Slots2D.exe!cocos2d::Label::drawSelf(bool visibleByCamera, cocos2d::Renderer * renderer, unsigned int flags) Line 1926	C++
 	Slots2D.exe!cocos2d::Label::visit(cocos2d::Renderer * renderer, const cocos2d::Mat4 & parentTransform, unsigned int parentFlags) Line 1911	C++
 	Slots2D.exe!cocos2d::ProtectedNode::visit(cocos2d::Renderer * renderer, const cocos2d::Mat4 & parentTransform, unsigned int parentFlags) Line 327	C++
 	Slots2D.exe!cocos2d::ui::Widget::visit(cocos2d::Renderer * renderer, const cocos2d::Mat4 & parentTransform, unsigned int parentFlags) Line 260	C++
 	Slots2D.exe!cocos2d::Node::visit(cocos2d::Renderer * renderer, const cocos2d::Mat4 & parentTransform, unsigned int parentFlags) Line 1248	C++
 	Slots2D.exe!cocos2d::Node::visit(cocos2d::Renderer * renderer, const cocos2d::Mat4 & parentTransform, unsigned int parentFlags) Line 1248	C++
 	Slots2D.exe!cocos2d::Scene::render(cocos2d::Renderer * renderer, const cocos2d::Mat4 & eyeTransform, const cocos2d::Mat4 * eyeProjection) Line 222	C++
 	Slots2D.exe!cocos2d::GLView::renderScene(cocos2d::Scene * scene, cocos2d::Renderer * renderer) Line 494	C++
 	Slots2D.exe!cocos2d::Director::drawScene() Line 293	C++

Aside from that, here is what I’ve noticed:

  • Some scenes take longer to render in Alpha1, so I’m literally staring at a blank screen for almost 1 second before sprites appear (EDIT: Seems to be in scenes with Spine sprites)
  • Alpha1 is using between 40-60% more memory for scenes with the exact same objects compared to 3.17.1, and I have absolutely no idea why [EDIT: It seems to have something to do with the new Spine runtime code that was modified to support this release of Cocos2d-x, where the Spine for Alpha1 is using 10x the memory for exactly the same Spine object]. The memory usage is visible in both Windows Task Manager and inside Visual Studio diagnostic tools. Is there something I should be aware of regarding memory usage?

EDIT: After running the Visual Studio performance profiler for memory analysis, these are the results:

V3.17.1:

Alpha1:

The excess memory usage seems to be coming from the modified Spine runtime, so perhaps there is a bug in the code added to support Cocos2d-x-metal. You can also see that the call count for the SkeletonTwoColorBatch::getInstance() is 44x more than the unmodified run-time in v3.17.1 (440,026 calls vs 10,066 calls).

Drilling down further into the SkeletonTwoColorBatch:

@R101 thanks for testing. About memory usage, it is because spine collect data itself, and send to backend buffer, we make try to combine them.

About call count, i think it is something about different spine version? We will double confirm it.

@R101 sorry, the above idea about buffer usage is wrong. It is something about metal’s design. When commands are commit, commands execution and engine logic are asynchronous. If engine wants to update buffer, then it needs to wait GPU to complete or create two buffers. In order to improve performance, engine creates two buffers.

So in order to save memory usage, use STATIC buffer as possible. The STATIC buffer means the buffer content is not updated every frame.

I applied the changes from the PR you linked earlier to the latest spine-cpp runtime v3.7 release, which is what I’m using in both cocos2d-x 3.17.1 and alpha1 in the tests I carried out. The call count seems to be specific to the changes made in the PR to support Cocos2d-x-metal, because without those changes, it only has 10K calls, yet with them, it’s 440K calls.

Also, unless I’ve missed something, the following methods are not being used in the SkeletonTwoColorBatch.cpp:

void TwoColorTrianglesCommand::draw(Renderer *r);

and 

void SkeletonTwoColorBatch::batch(cocos2d::Renderer *renderer, TwoColorTrianglesCommand* command) ;

I don’t entirely understand the code, but would the fact that these methods aren’t used indicate that no batching is taking place whatsoever?

1 Like

Ok, i will ask the PR’s author to take a look. But it is wired that, the PR can work on v3.17, because it based on new backend.

Sorry no, that’s not what I meant. What I meant is I used the latest release of Spine v3.7 runtime for Cocos2d-x on 3.17.1, which worked as intended. What I did then is apply the changes to it from the PR, and then used that modified version with the new backend.

The test was done with a single Spine animation, and it’s very concerning that this resulted in 10x the memory usage, and 44x the calls (it’s visibly slow to load), compared to the unmodified Spine 3.7 runtime. I honestly do think that there is something not right with the modified code in that PR, or something related to it that’s causing this issue.

Thanks for explanation.

Hi @R101, I am the author of this PR. and thanks for your testing.
I did some comparisons with v3 and found that it did take much longer on spine-runtime initialization. On startup, the spine-runtime will allocate 10,000 commands for later usage. The alpha version did too much on render command construction procedure. I have pushed a commit here, please let me know if this can help.

1 Like

@PatriceJiang Thank you for looking into this issue. I just tested the changes you made in the new commit, and all I can say is that the difference is amazing! Seriously, whatever you did actually helped a lot, and you have managed to cut down the number of calls made significantly. There is no longer a noticeable delay when the scene is loading, and it’s almost as fast as Spine on Cocos2d-x 3.17.1.

Memory usage in the Spine for Alpha1 is still around 3x higher than Spine for v3.17.1, and for the specific animation I’m using, it’s a little over 20MB difference. It’s not a big deal, but it would be great if it was lower, since this is only a single animation.

Overall though, it’s really great work, so thank you for taking the time to work on adapting Spine to the new Cocos2d-x rendering code.

In case it helps, here is the memory profiler result:

@R101 now it uses two buffers, these buffers are allocated in CPU side, so the GPU memory will be reduced as i think. And i think it is about 2x memory used. We will dig more into it.

1 Like

@zhangxm Thank you very much for looking into it.