Crash in cloned gradient Shader
-
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 -
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. -
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,