<div dir="ltr"><div>Hi Dmitry,</div><div><br></div><div>Thank you for your answer. <br></div><div><br></div><div>It was also my first thought, that the blocking by 
image->immediateLockForReadOnly() causes the problem and that waiting for the end of the stroke by calling 
 barrierLock() would just take too long to satisfy the 10Hz condition.</div><div>But then I wondered, where the data comes from and how it is possible to explain the strange behaviour I observed. Am I right, that with 
<code><span class="gmail-"><br></span></code></div><div><code><span class="gmail-"><br></span></code></div><div><code><span class="gmail-">device-></span><span class="gmail-hljs-built_in">makeCloneFromRough</span><span class="gmail-">(image-></span><span class="gmail-hljs-built_in">projection</span><span class="gmail-">()</span><span class="gmail-">, image-></span><span class="gmail-hljs-built_in">bounds</span><span class="gmail-">()</span><span class="gmail-">)</span><span class="gmail-">;</span></code></div><div><br></div><div>we just create a new clone of our image without any data? And that the real data, we are building our PNG and JPEG exports on, comes from this read call:</div><div><br></div><div>
<code><span class="gmail-">device-></span><span class="gmail-hljs-built_in">readBytes</span><span class="gmail-">(</span><span class="gmail-hljs-built_in">reinterpret_cast</span><span class="gmail-"><quint8 *></span><span class="gmail-">(imageBuffer.</span><span class="gmail-hljs-built_in">data</span><span class="gmail-">()</span><span class="gmail-">)</span><span class="gmail-">, </span><span class="gmail-hljs-number">0</span><span class="gmail-">, </span><span class="gmail-hljs-number">0</span><span class="gmail-">, width, height)</span><span class="gmail-">;</span></code> <br></div><div><br></div><div>I would imagine that the second command needs far more time than the first one. And that this data must be continuously updated by the painting engine somehow. And that the strange data, I get exported, must in the end come from this read call instead of the clone call. </div><div>But please correct me, if my thoughts are wrong. I really would like to understand Krita better in this place.</div><div><br></div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div>
 It would make the framerate of the final production not very stable (though I'm not sure if it is a problem)

</div></blockquote><div><br></div><div>Actually, four our use case, this is a problem (unfortunately). My wife and I are producing tutorial videos. We make them by a mixture of live screen capturing of the tool we want to show and by hand drawing comic style sketches to explain a theory or to show something in the screen capturing. Until now, we are using OBS to get our raw material, but this has many disadvantages. It would be so cool, if we just could use the krita recorder tool directly. It would save us so much work and the video quality would be way better. But to use it, we must achieve at least a frame rate of 30Hz. Therefore, I introduced a new Real Time Feature for the Krita recorder plugin (<a href="https://invent.kde.org/freiser/krita-freiser/-/tree/freiser/RecorderRealTimeMT?ref_type=heads">https://invent.kde.org/freiser/krita-freiser/-/tree/freiser/RecorderRealTimeMT?ref_type=heads</a>), which works really smooth. But naturally, the bug hits us here in the same way. For big colored areas, which are drawn in a short period, we receive white frames and the areas are not build up as expected in the exported video. Everything else, especially fine brush strokes are recorded smooth and in the expected frame rate.</div><div><br></div><div>If you like this new real time feature, I would be honored if you will accept my merge request as soon as I'm done with the cleanup. But I fear, with the bug still there, it doesn't make much sense to integrate it.</div><div><br></div><div><br></div><div>Back to the bug. I thought a little bit about it and did some research on the Krita code. As it turns out, you use the Qt OpenGl Render engine in many places. Especially the KisOpenGLCanvasRenderer caught my interest. If it were possible for the recorder to access the framebuffer, we would probably be many times faster at capturing the current image than by the current method, wouldn't we? But it's just an idea and before I start investigating in this direction, I would be curious about your opinion. Do you think it makes sense to rebuild the capturing code by using OpenGL?<br></div><div><br></div><div>Florian<br></div><div> <br></div><div> </div><div><br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">Am Mi., 1. Nov. 2023 um 08:59 Uhr schrieb Dmitry Kazakov <<a href="mailto:dimula73@gmail.com">dimula73@gmail.com</a>>:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">Hi, Florian!<div><br></div><div>The problem happens a bit higher in the hierarchy. The problem is that the recorder does not wait for the stroke to finish. Instead it just locks the image for read-only in the middle of the action and reads the data. You can see that in this piece of code:</div><div><br></div><div>image->immediateLockForReadOnly();<br>device->makeCloneFromRough(image->projection(), image->bounds());<br>image->unlock()<br></div><div><br></div><div>The only wait to avoid white/incomplete frames in the recorder is to make snapshots "between" the strokes. There are two ways to achieve that: either use barrierLock() (not-recommended) or create a stroke that makes a copy of the image. Just like Overview and Channels dockers do. The only problem with this approach is that the 100ms timing will not be satisfied in this case. The recorder would wait for the user's stroke to end (which might easily take more than 100ms) and then just add a frame. It would make the framerate of the final production not very stable (though I'm not sure if it is a problem).</div><div><br></div><div>Alternatively, we could implement an epoche-based brush updates, but that is a huge ton of work. We wanted to implement that to handle tearing in the updates back in 2018, but never had time to actually implement that.</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Tue, Oct 31, 2023 at 12:38 PM Florian Reiser <<a href="mailto:reiserfm@gmail.com" target="_blank">reiserfm@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div>Hi everyone,</div><div><br></div><div>not sure if this is the right channel to ask this. I hope this mail reaches some of the right people.</div><div><br></div><div>I've created a bug report for the newest Krita Version (<a href="https://bugs.kde.org/show_bug.cgi?id=476326" target="_blank">https://bugs.kde.org/show_bug.cgi?id=476326</a>). But I think the bug only showed up just yet, because with Krita 5.2 we introduced the 10Hz recording feature. There is a good chance that it has already existed for quite some time. <br></div><div><br></div><div>Can someone support me to fix it. We really want to use the new 10Hz Feature for one of our projects, it would reduce our post production work a lot.</div><div><br></div><div>Thank you very much for your help</div><div>Florian<br></div></div>
</blockquote></div><br clear="all"><div><br></div><span class="gmail_signature_prefix">-- </span><br><div dir="ltr" class="gmail_signature">Dmitry Kazakov</div>
</blockquote></div>