Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush Python API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Crash in cloned gradient Shader

    SDK Help
    0
    3
    498
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • H
      Helper
      last edited by

      On 10/10/2017 at 04:55, xxxxxxxx wrote:

      User Information:
      Cinema 4D Version:    
      Platform:      Mac OSX  ; 
      Language(s) :     C++  ;

      ---------
      Hi!

      One of our shaders is used as a "reference shader" where you can link a shader from anywhere else
      in the document (in this case, the shader sits on a BaseObject) and reproduce it. On InitRender(), this
      referenced shader is cloned and inserted into a temporary branch to ensure that the shader is available
      to the document.

      In case it matters, this "reference shader" sits on the very same object, too.

      Unfortunately, a crash appears quite frequently when we copy the BaseObject that hosts both shaders.
      This crash is only reproducible when the source shader is a Gradient Shader. It appears to happen only
      when the object is copied multiple times at once or in a short period of time. Also, I wasn't able to
      reproduce this issue on Windows.

      Is there anything special about the Gradient shader that could prevent it from being sampled this way?

      > INITRENDERRESULT ReferenceShader::InitRender(
      >
      > BaseShader* shader, const InitRenderStruct& irs)
      >
      > {
      >
      > BaseContainer* bc = (shader ? shader->GetDataInstance() : nullptr);
      >
      > if (!shader || !bc) return INITRENDERRESULT_UNKNOWNERROR;
      >
      > if (!m_head) return INITRENDERRESULT_OUTOFMEMORY;
      >
      >
      >
      >
      > // We pass nullptr for the document because we do actually want to allow
      >
      > // retrieving a shader from another document (for the shader preview).
      >
      > m_subShader = (BaseShader*) bc->GetLink(FIXTURESHADER_SUBSHADER, nullptr, Xbase);
      >
      > if (m_subShader) {
      >
      > // Check if the shader is in the hierarchy.
      >
      > Bool needsClone = true;
      >
      > for (BaseShader* curr = shader->GetDown(); curr; curr = curr->GetNext()) {
      >
      > if (curr == m_subShader) {
      >
      > needsClone = false;
      >
      > break;
      >
      > }
      >
      > }
      >
      >
      >
      >
      > m_subShaderCloned = needsClone;
      >
      > if (needsClone) {
      >
      > m_subShader = (BaseShader*) m_subShader->GetClone(COPYFLAGS_0, nullptr);
      >
      > if (!m_subShader) return INITRENDERRESULT_OUTOFMEMORY;
      >
      > m_head->InsertLast(m_subShader); // Needs to be removed and deallocated in FreeRender()
      >
      > }
      >
      >
      >
      >
      > auto res = m_subShader->InitRender(irs);
      >
      > if (res != INITRENDERRESULT_OK) {
      >
      > if (m_subShaderCloned) BaseShader::Free(m_subShader);
      >
      > m_subShader = nullptr;
      >
      > return res;
      >
      > }
      >
      > }
      >
      >
      >
      >
      > // ...
      >
      > return INITRENDERRESULT_OK;
      >
      > }
      >
      >
      >
      >
      >
      > void ReferenceShader::FreeRender(BaseShader* shader)
      >
      > {
      >
      > if (m_subShader) {
      >
      > m_subShader->FreeRender();
      >
      > if (m_subShaderCloned) {
      >
      > m_subShader->Remove();
      >
      > BaseShader::Free(m_subShader);
      >
      > }
      >
      > m_subShader = nullptr;
      >
      > }
      >
      >
      >
      >
      > // ...
      >
      > }
      >
      >
      >
      >
      >
      > Vector ReferenceShader::Output(BaseShader* shader, ChannelData* cd) {
      >
      > // ...
      >
      >
      >
      >
      > Float u, v = ...;
      >
      >
      >
      >
      > if (m_subShader) {
      >
      > ChannelData data = *cd;
      >
      > data.p = Vector(u, v, 0);
      >
      > return m_subShader->Sample(&data) * m_sampling.brightness; // << CRASH when m_subShader is a Gradient Shader
      >
      > }
      >
      >
      >
      >
      > // ...
      >
      > return Vector();
      >
      > }
      >
      > Int32 ReferenceShader::GetBranchInfo(
      >
      > GeListNode* node, BranchInfo* branches,
      >
      > Int32 max, GETBRANCHINFO flags)
      >
      > {
      >
      > Int32 count = 0;
      >
      > if (count < max) {
      >
      > branches[count].head = m_head;
      >
      > branches[count].name = nullptr;
      >
      > branches[count].id = Xbase;
      >
      > branches[count].flags = BRANCHINFOFLAGS_HIDEINTIMELINE;
      >
      > count++;
      >
      > }
      >
      > return count;
      >
      > }

      Tips or hints are also appreciated, of course. 🙂

      Thanks,
      -Niklas

      1 Reply Last reply Reply Quote 0
      • H
        Helper
        last edited by

        On 11/10/2017 at 01:26, xxxxxxxx wrote:

        Hi Niklas,

        we are not aware of any peculiarities of the gradient shader.
        Can you provide us with a crash report (e.g. via email)? Another option could be to provide us with your plugin, so we could dig into the crash.

        1 Reply Last reply Reply Quote 0
        • H
          Helper
          last edited by

          On 18/10/2017 at 06:06, xxxxxxxx wrote:

          Thanks to the SDK support team, they figured out that ChannelData::texflag was set so that
          GET_TEX_CHANNEL() would return CHANNEL_BUMP, which in turn requires ChannelData::vd
          to be not-nullptr. The issue on my side was a bit further up the call stack, where I created a
          new ChannelData on the stack without initializing the texflag member (the ChannelData
          constructor only sets vd = nullptr, leaving texflag at a random value).

          > /* Returns an empty ChannelData object. The default constructor only explicitly initializes
          >
          > * the #ChannelData::vd member, leaving #ChannelData::texflag and others at a random value.
          >
          > * This random value for texflag can be especially problematic when it results in
          >
          > * #GET_TEX_CHANNEL() to return #CHANNEL_BUMP, which requires #ChannelData::vd to be set,
          >
          > * leading to crashes in for example the C4D gradient shader.
          >
          > */
          >
          > inline ChannelData GetEmptyChannelData() {
          >
          > ChannelData r;
          >
          > r.t = 0.0;
          >
          > r.texflag = 0;
          >
          > r.off = 0.0;
          >
          > r.scale = 0.0;
          >
          > return r;
          >
          > }

          Cheers,

          1 Reply Last reply Reply Quote 0
          • First post
            Last post