<div class="gmail_quote">On Tue, Oct 12, 2010 at 1:20 PM, Maciej Stachowiak <span dir="ltr">&lt;<a href="mailto:mjs@apple.com">mjs@apple.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<div style="word-wrap:break-word"><div><div></div><div class="h5"><br><div><div>On Oct 12, 2010, at 12:44 PM, James Robinson wrote:</div><br><blockquote type="cite"><div class="gmail_quote">On Tue, Oct 12, 2010 at 9:47 AM, Chris Marrin <span dir="ltr">&lt;<a href="mailto:cmarrin@apple.com" target="_blank">cmarrin@apple.com</a>&gt;</span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

<div><div></div><div><br>
On Oct 11, 2010, at 5:15 PM, Maciej Stachowiak wrote:<br>
<br>
&gt;<br>
&gt; On Oct 11, 2010, at 4:03 PM, Chris Marrin wrote:<br>
&gt;<br>
&gt;&gt;<br>
&gt;&gt; On Oct 11, 2010, at 3:35 PM, James Robinson wrote:<br>
&gt;&gt;<br>
&gt;&gt;&gt; On Mon, Oct 11, 2010 at 3:15 PM, Chris Marrin &lt;<a href="mailto:cmarrin@apple.com" target="_blank">cmarrin@apple.com</a>&gt; wrote:<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; For accelerated 2D rendering we created a class called DrawingBuffer. This encapsulates the accelerated drawing surface (usually in the GPU) and the compositing layer used to display that surface on the page. The drawing surface (which is called a Framebuffer Object or FBO) is allocated by GraphicsContext3D, so DrawingBuffer needs a reference to that. Currently this is a weak reference. DrawingBuffer has a ::create() method and you pass the GraphicsContext3D to that method.<br>



&gt;&gt;&gt;<br>
&gt;&gt;&gt; If you destroy the GraphicsContext3D, DrawingBuffer has a stale pointer. If you were to try to destroy the DrawingBuffer it would attempt to use that pointer (to destroy its FBO) and crash or worse. Currently we have an implicit policy that you should never destroy a GraphicsContext3D before its DrawingBuffers are all destroyed. That works fine in the current use case, CanvasRenderingContext2D. And we can follow that same policy when in the future when we use DrawingBuffer in WebGLRenderingContext.<br>



&gt;&gt;&gt;<br>
&gt;&gt;&gt; My concern is that this sort of implicit policy can lead to errors in the future when other potential clients of these classes use them. So I posted <a href="https://bugs.webkit.org/show_bug.cgi?id=47501" target="_blank">https://bugs.webkit.org/show_bug.cgi?id=47501</a>. In that patch I move the creation of DrawingBuffer to the GraphicsContext3D and keep back pointers to all the DrawingBuffers allocated so they can be cleaned up when GraphicsContext3D is destroyed. In talking to James R. he&#39;s concerned this adds unnecessary complexity and would rather stick with the implicit policy.<br>



&gt;&gt;&gt;<br>
&gt;&gt;&gt; So is this something I should be concerned about, or is an implicit policy sufficient in this case?<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; Before somebody suggests it, I think Chris and I are in agreement that neither GraphicsContext3D nor DrawingBuffer should be RefCounted.  They both have clear single-ownership semantics.<br>
&gt;&gt;<br>
&gt;&gt; True, although Simon and I just chatted and he pointed out that Refcounting both classes would solve this problem. The fact that GraphicsContext3D wouldn&#39;t need a back pointer to DrawingBuffer means we wouldn&#39;t have any circular references. I don&#39;t think the overhead of refcounting is an issue here, so maybe that would be a simpler solution?<br>



&gt;<br>
&gt; I think having two independent objects that must be deleted in a specific order, or else you crash, is a hazardous design. APIs (even internal APIs) are better when they do not have a way to be &quot;used wrong&quot;. So, I think this should be changed one way or the other.<br>



&gt;<br>
&gt; I have to say that to my taste, refcounting seems like a cleaner solution than ad-hoc weak pointers. I&#39;m skeptical of the claim that refcounting is not good for a heavyweight object. If there&#39;s really a time when special resources (VRAM, etc) need to be freed at a known point in program code, then it may be better to have an explicit &quot;close&quot; type function instead of counting on the destructor. On the other hand, this might end up being roughly equivalent to the &quot;clear backpointers&quot; solution, but moves the complexity of being in a possibly-invalid state from DrawingBuffer to GraphicsContext3D.<br>



&gt;<br>
&gt; Either way, I am pretty confident that a design where objects must be destroyed in a specific order is not the best choice.<br>
<br>
</div></div>So it seems like we have two choices: 1) my current patch, which uses backpointers to manage the lifetime of the weak pointers, or 2) refcounting. My current approach has the advantage that the resources are cleared as soon as the DrawingBuffer is destroyed. But it is more complex and therefore more error prone. I think that complexity is manageable so that would be my preferred implementation. But refcounting is simpler and my current patch has a clear() method on DrawingBuffer which gets rid of all the resources. I could leave that method and change to a refcounted model, so the author can control when the resources are destroyed.<br>


</blockquote><div><br></div><div>Another option would be to generalize the WeakPtr&lt;T&gt; implementation from that patch into a generic class and use that.  Then that logic could be implemented, reviewed and tested independently from the graphics code.  I know that Maciej has expressed concern about this pattern in the past due to the runtime cost it imposes.</div>

<div><br></div><div>Ref counting is a fairly blunt instrument but it would fit in best with the rest of the codepath.</div></div></blockquote><br></div></div></div><div>Weak pointers are both more complicated than refcounting and introduce a comparable or possibly even greater level of runtime cost. So if there&#39;s ever a problem that can be solved either way, I would tend to prefer refcounting.</div>
<div><br></div><div>Regards,</div><div>Maciej</div><div><br></div></div></blockquote><div><br></div><div><br></div><div>Hmm, I&#39;ve found weak pointer abstractions to be very useful.  The issue with reference counting is that it is &quot;easy&quot; to introduce memory leaks, and has been mentioned, it is sometimes nice to have deterministic object destruction.</div>
<div><br></div><div>It is also nice to avoid having to have explicit clear() functions and then add checks to every other method to assert that they are not called after clear().</div><div><br></div><div>In the Chromium code base, we have a helper for weak pointers:</div>
<div><a href="http://src.chromium.org/viewvc/chrome/trunk/src/base/weak_ptr.h?view=markup">http://src.chromium.org/viewvc/chrome/trunk/src/base/weak_ptr.h?view=markup</a></div><div><br></div><div>We tend to use this in cases in which:</div>
<div><br></div><div>1) there are many consumers interested in holding a back pointer to some shared resource, and</div><div>2) we&#39;d like the shared resource to die at some predictable time.</div><div><br></div><div>Without a utility like this, the alternative is to make the shared resource notify each of the consumers about the impending destruction of the shared resource.</div>
<div><br></div><div>It is true that WeakPtr&lt;T&gt; adds a null check in front of each method call made by the consumers, but that runtime cost is often justified in exchange for reduced code complexity (i.e., eliminating the need to notify consumers when the shared resource dies).</div>
<div><br></div><div>Regards,</div><div>-Darin</div></div>