Note that there are some explanatory texts on larger screens.

plurals
  1. POCalculate average of pixels in the front buffer of the gpu without copying the front buffer back to system memory
    text
    copied!<p>I am preparing to build a clone of the ambilight for my pc. For this purpose I need a way to calculate the average color of several areas of the screen. </p> <p>The fastest way I have found so far is the following:</p> <pre><code> pd3dDevice-&gt;CreateOffscreenPlainSurface(ddm.Width, ddm.Height, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH/*D3DPOOL_SYSTEMMEM*/, &amp;pSurface, nullptr) pd3dDevice-&gt;GetFrontBufferData(0, pSurface); D3DLOCKED_RECT lockedRect; pSurface-&gt;LockRect(&amp;lockedRect, nullptr, D3DLOCK_NO_DIRTY_UPDATE|D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY); memcpy(pBits, (unsigned char*) lockedRect.pBits, dataLength); pSurface-&gt;UnlockRect(); //calculate average over of pBits </code></pre> <p>However it involes copying the whole front buffer back to the system memory which takes 33 ms on average. Obviuosly 33ms is no way near the speed that I need for a decent update rate therefore I am looking for a way to calculate the average over a region of the front buffer directly on the gpu without copying the front buffer back to the system memory.</p> <p>edit: the bottleneck in the code snippet is <code>pd3dDevice-&gt;GetFrontBufferData(0, pSurface);</code>. The memcpy has no visible effect on performance.</p> <p><strong>edit:</strong></p> <p>Based on user3125280's answer i cooked up a pice of code that should take the top left corner of the screen and average it. However the result is always 0. What am I missing? Also notice that <code>pSurface</code> is now in video memory and thus <code>GetFrontBufferData</code> is just a memcpy in video ram which is super fast.</p> <pre><code> pd3dDevice-&gt;CreateOffscreenPlainSurface(1, 1, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &amp;pAvgSurface, nullptr); pd3dDevice-&gt;CreateOffscreenPlainSurface(ddm.Width, ddm.Height, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &amp;pSurface, nullptr); pd3dDevice-&gt;GetFrontBufferData(0, pSurface); RECT r; r.right = 100; r.bottom = 100; r.left = 0; r.top = 0; pd3dDevice-&gt;StretchRect(pSurface, &amp;r, pAvgSurface, nullptr, D3DTEXF_LINEAR); D3DLOCKED_RECT lockedRect; pAvgSurface-&gt;LockRect(&amp;lockedRect, nullptr, D3DLOCK_NO_DIRTY_UPDATE|D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY); unsigned int color = -1; memcpy((unsigned char*) &amp;color, (unsigned char*) lockedRect.pBits, 4); //FIXME there has to be a better way than memcopy pAvgSurface-&gt;UnlockRect(); </code></pre> <p><strong>edit2:</strong> Apparantly <code>GetFrontBufferData</code> requires the target to reside in the system memory. So I am back to square one.</p> <p><strong>edit3:</strong> According to <a href="http://www.virtualdub.org/blog/pivot/entry.php?id=356" rel="nofollow">this</a> the following should be possible in DX11.1:</p> <ul> <li>Create a Direct3D 11.1 device. (Maybe earlier works too -- I haven't tried. I'm not sure there's a reason to use a D3D10/10.1/11 device anyway.)</li> <li>Find the IDXGIOutput you want to duplicate, and call DuplicateOutput() to get an IDXGIOutputDuplication interface.</li> <li>Call AcquireNextFrame() to wait for a new frame to arrive.</li> <li>Process the received texture.</li> <li>Call ReleaseFrame().</li> <li>Repeat.</li> </ul> <p>However due to my non existing knowledge of DirectX I am having a hard time implementing it.</p> <p><strong>edit4:</strong> DuplicateOutput is not supported in operating systems older than Windows 8 :(</p> <p><strong>edit5:</strong> I did some experiments with the classical <code>GetPixel</code> API thinking that it may be fast enough for random sampling. Sadly it is not. <code>GetPixel</code> takes the same amount of time that <code>GetFrontBufferData</code> takes. I guess it internally calls <code>GetFrontBufferData</code>.</p> <p>So for now I see two solutions: * Disable Aero and use <code>GetFrontBufferData</code> * Switch to windows 8 Both of them are not really good :(</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload