<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title><![CDATA[Серый форум &mdash; AHK: сохранение экрана через DirectX11 + Gdip]]></title>
		<link>http://forum.script-coding.com/viewtopic.php?id=17671</link>
		<atom:link href="http://forum.script-coding.com/extern.php?action=feed&amp;tid=17671&amp;type=rss" rel="self" type="application/rss+xml" />
		<description><![CDATA[Недавние сообщения в теме «AHK: сохранение экрана через DirectX11 + Gdip».]]></description>
		<lastBuildDate>Sun, 12 Mar 2023 14:57:00 +0000</lastBuildDate>
		<generator>PunBB</generator>
		<item>
			<title><![CDATA[AHK: сохранение экрана через DirectX11 + Gdip]]></title>
			<link>http://forum.script-coding.com/viewtopic.php?pid=157117#p157117</link>
			<description><![CDATA[<p><strong>iseahound</strong> с оф.форума сделал замеры, которые показали, что сохранять экран в картинку быстрее через gdip чем через wic.<br />А получать экран быстрее через directx9 чем через gdip.<br />Я решил протестировать с directx11, получилось еще быстрее, но обнаружил баг на 144 герцовом мониторе.<br />При использовании IDXGIOutputDuplication::AcquireNextFrame надо проверять LastPresentTime.<br />Данный пример создает 100 скриншотов и сохраняет в директорию скрипта 1.png-100.png. <br /></p><div class="codebox"><pre><code>setbatchlines -1
; Load GDI+
DllCall(&quot;LoadLibrary&quot;, &quot;str&quot;, &quot;gdiplus&quot;)
VarSetCapacity(si, A_PtrSize = 8 ? 24 : 16, 0) ; sizeof(GdiplusStartupInput) = 16, 24
NumPut(0x1, si, &quot;uint&quot;)
DllCall(&quot;gdiplus\GdiplusStartup&quot;, &quot;ptr*&quot;, pToken:=0, &quot;ptr&quot;, &amp;si, &quot;ptr&quot;, 0)
extension := &quot;png&quot;
DllCall(&quot;gdiplus\GdipGetImageEncodersSize&quot;, &quot;uint*&quot;, count:=0, &quot;uint*&quot;, size:=0)
VarSetCapacity(ci, size)
DllCall(&quot;gdiplus\GdipGetImageEncoders&quot;, &quot;uint&quot;, count, &quot;uint&quot;, size, &quot;ptr&quot;, &amp;ci)
if !(count &amp;&amp; size)
   throw Exception(&quot;Could not get a list of image codec encoders on this system.&quot;)
Loop % count
   EncoderExtensions := StrGet(NumGet(ci, (idx:=(48+7*A_PtrSize)*(A_Index-1))+32+3*A_PtrSize, &quot;uptr&quot;), &quot;UTF-16&quot;)
      until InStr(EncoderExtensions, &quot;*.&quot; extension)
if !(pCodec := &amp;ci + idx)
   throw Exception(&quot;Could not find a matching encoder for the specified file format.&quot;)

IDXGIFactory := CreateDXGIFactory()
if !IDXGIFactory
{
   MsgBox, 16, Error, Create IDXGIFactory failed.
   ExitApp
}
loop
{
   IDXGIFactory_EnumAdapters(IDXGIFactory, A_Index-1, IDXGIAdapter)
   loop
   {
      hr := IDXGIAdapter_EnumOutputs(IDXGIAdapter, A_Index-1, IDXGIOutput)
      if (hr = &quot;DXGI_ERROR_NOT_FOUND&quot;)
         break
      VarSetCapacity(DXGI_OUTPUT_DESC, 88+A_PtrSize, 0)
      IDXGIOutput_GetDesc(IDXGIOutput, &amp;DXGI_OUTPUT_DESC)
      Width := NumGet(DXGI_OUTPUT_DESC, 72, &quot;int&quot;)
      Height := NumGet(DXGI_OUTPUT_DESC, 76, &quot;int&quot;)
      AttachedToDesktop := NumGet(DXGI_OUTPUT_DESC, 80, &quot;int&quot;)
      if (AttachedToDesktop = 1)
         break 2     
      ObjRelease(IDXGIOutput)    
   }
   ObjRelease(IDXGIAdapter)
}
if (AttachedToDesktop != 1)
{
   MsgBox, 16, Error, No adapter attached to desktop
   ExitApp
}
D3D11CreateDevice(IDXGIAdapter, D3D_DRIVER_TYPE_UNKNOWN := 0, 0, 0, 0, 0, D3D11_SDK_VERSION := 7, d3d_device, 0, d3d_context)
IDXGIOutput1 := IDXGIOutput1_Query(IDXGIOutput)
IDXGIOutput1_DuplicateOutput(IDXGIOutput1, d3d_device, Duplication)
VarSetCapacity(DXGI_OUTDUPL_DESC, 36, 0)
IDXGIOutputDuplication_GetDesc(Duplication, &amp;DXGI_OUTDUPL_DESC)
DesktopImageInSystemMemory := NumGet(DXGI_OUTDUPL_DESC, 32, &quot;uint&quot;)
sleep 50   ; As I understand - need some sleep for successful connecting to IDXGIOutputDuplication interface

VarSetCapacity(D3D11_TEXTURE2D_DESC, 44, 0)
NumPut(width, D3D11_TEXTURE2D_DESC, 0, &quot;uint&quot;)   ; Width
NumPut(height, D3D11_TEXTURE2D_DESC, 4, &quot;uint&quot;)   ; Height
NumPut(1, D3D11_TEXTURE2D_DESC, 8, &quot;uint&quot;)   ; MipLevels
NumPut(1, D3D11_TEXTURE2D_DESC, 12, &quot;uint&quot;)   ; ArraySize
NumPut(DXGI_FORMAT_B8G8R8A8_UNORM := 87, D3D11_TEXTURE2D_DESC, 16, &quot;uint&quot;)   ; Format
NumPut(1, D3D11_TEXTURE2D_DESC, 20, &quot;uint&quot;)   ; SampleDescCount
NumPut(0, D3D11_TEXTURE2D_DESC, 24, &quot;uint&quot;)   ; SampleDescQuality
NumPut(D3D11_USAGE_STAGING := 3, D3D11_TEXTURE2D_DESC, 28, &quot;uint&quot;)   ; Usage
NumPut(0, D3D11_TEXTURE2D_DESC, 32, &quot;uint&quot;)   ; BindFlags
NumPut(D3D11_CPU_ACCESS_READ := 0x20000, D3D11_TEXTURE2D_DESC, 36, &quot;uint&quot;)   ; CPUAccessFlags
NumPut(0, D3D11_TEXTURE2D_DESC, 40, &quot;uint&quot;)   ; MiscFlags
ID3D11Device_CreateTexture2D(d3d_device, &amp;D3D11_TEXTURE2D_DESC, 0, staging_tex)

a := a_tickcount
loop 100
{
   tooltip % A_Index
   VarSetCapacity(DXGI_OUTDUPL_FRAME_INFO, 48, 0)
   if (A_Index = 1)
   {
      loop
      {
         AcquireNextFrame := IDXGIOutputDuplication_AcquireNextFrame(Duplication, -1, &amp;DXGI_OUTDUPL_FRAME_INFO, desktop_resource)
         LastPresentTime := NumGet(DXGI_OUTDUPL_FRAME_INFO, 0, &quot;int64&quot;)
         if (LastPresentTime &gt; 0)
            break
         ObjRelease(desktop_resource)
         IDXGIOutputDuplication_ReleaseFrame(duplication)
      }
   }
   else
   {
      AcquireNextFrame := IDXGIOutputDuplication_AcquireNextFrame(Duplication, 0, &amp;DXGI_OUTDUPL_FRAME_INFO, desktop_resource)
      LastPresentTime := NumGet(DXGI_OUTDUPL_FRAME_INFO, 0, &quot;int64&quot;)
   }
   if (AcquireNextFrame != &quot;DXGI_ERROR_WAIT_TIMEOUT&quot;)
   {
      if (LastPresentTime &gt; 0)
      {
         if (DesktopImageInSystemMemory = 1)
         {
            VarSetCapacity(DXGI_MAPPED_RECT, A_PtrSize*2, 0)
            IDXGIOutputDuplication_MapDesktopSurface(Duplication, &amp;DXGI_MAPPED_RECT)
            pitch := NumGet(DXGI_MAPPED_RECT, 0, &quot;int&quot;)
            pBits := NumGet(DXGI_MAPPED_RECT, A_PtrSize, &quot;ptr&quot;)
         }
         else
         {
            tex := ID3D11Texture2D_Query(desktop_resource)
            ID3D11DeviceContext_CopyResource(d3d_context, staging_tex, tex)
            VarSetCapacity(D3D11_MAPPED_SUBRESOURCE, 8+A_PtrSize, 0)
            ID3D11DeviceContext_Map(d3d_context, staging_tex, 0, D3D11_MAP_READ := 1, 0, &amp;D3D11_MAPPED_SUBRESOURCE)
            pBits := NumGet(D3D11_MAPPED_SUBRESOURCE, 0, &quot;ptr&quot;)
            pitch := NumGet(D3D11_MAPPED_SUBRESOURCE, A_PtrSize, &quot;uint&quot;)
         }
      }
   }
   DllCall(&quot;gdiplus\GdipCreateBitmapFromScan0&quot;, &quot;int&quot;, width, &quot;int&quot;, height, &quot;int&quot;, pitch, &quot;int&quot;, 0xE200B, &quot;ptr&quot;, pBits, &quot;ptr*&quot;, pBitmap:=0)
   DllCall(&quot;gdiplus\GdipSaveImageToFile&quot;, &quot;ptr&quot;, pBitmap, &quot;wstr&quot;, A_Index &quot;.png&quot;, &quot;ptr&quot;, pCodec, &quot;uint&quot;, 0)
   DllCall(&quot;gdiplus\GdipDisposeImage&quot;, &quot;ptr&quot;, pBitmap)
   if (AcquireNextFrame != &quot;DXGI_ERROR_WAIT_TIMEOUT&quot;)
   {
      if (LastPresentTime &gt; 0)
      {
         if (DesktopImageInSystemMemory = 1)
            IDXGIOutputDuplication_UnMapDesktopSurface(Duplication)
         else
         {
            ID3D11DeviceContext_Unmap(d3d_context, staging_tex, 0)
            ObjRelease(tex)
         }
      }
      ObjRelease(desktop_resource)
      IDXGIOutputDuplication_ReleaseFrame(duplication)
   }
}
msgbox % a_tickcount - a
Release(staging_tex)
Release(d3d_device)
Release(d3d_context)
Release(duplication)
Release(IDXGIAdapter)
Release(IDXGIOutput)
Release(IDXGIOutput1)
Release(IDXGIFactory)
ExitApp




CreateDXGIFactory()
{
   if !DllCall(&quot;GetModuleHandle&quot;,&quot;str&quot;,&quot;DXGI&quot;)
      DllCall(&quot;LoadLibrary&quot;,&quot;str&quot;,&quot;DXGI&quot;)
   if !DllCall(&quot;GetModuleHandle&quot;,&quot;str&quot;,&quot;D3D11&quot;)
      DllCall(&quot;LoadLibrary&quot;,&quot;str&quot;,&quot;D3D11&quot;)
   GUID(riid, &quot;{7b7166ec-21c7-44ae-b21a-c9ae321ae369}&quot;)
   hr := DllCall(&quot;DXGI\CreateDXGIFactory1&quot;, &quot;ptr&quot;, &amp;riid, &quot;ptr*&quot;, ppFactory)
   if hr or ErrorLevel
      _Error(A_ThisFunc &quot; error: &quot; hr &quot;`nErrorLevel: &quot; ErrorLevel)
   return ppFactory
}

IDXGIFactory_EnumAdapters(this, Adapter, ByRef ppAdapter)
{
   hr := DllCall(NumGet(NumGet(this+0)+7*A_PtrSize), &quot;ptr&quot;, this, &quot;uint&quot;, Adapter, &quot;ptr*&quot;, ppAdapter)
   if hr or ErrorLevel
      _Error(A_ThisFunc &quot; error: &quot; hr &quot;`nErrorLevel: &quot; ErrorLevel)
}

IDXGIAdapter_EnumOutputs(this, Output, ByRef ppOutput)
{
   hr := DllCall(NumGet(NumGet(this+0)+7*A_PtrSize), &quot;ptr&quot;, this, &quot;uint&quot;, Output, &quot;ptr*&quot;, ppOutput)
   if hr or ErrorLevel
   {
      if (hr&amp;=0xFFFFFFFF) = 0x887A0002   ; DXGI_ERROR_NOT_FOUND
         return &quot;DXGI_ERROR_NOT_FOUND&quot;
      _Error(A_ThisFunc &quot; error: &quot; hr &quot;`nErrorLevel: &quot; ErrorLevel)
   }
}

IDXGIAdapter_GetDesc(this, pDesc)
{
   hr := DllCall(NumGet(NumGet(this+0)+8*A_PtrSize), &quot;ptr&quot;, this, &quot;ptr&quot;, pDesc)
   if hr or ErrorLevel
      _Error(A_ThisFunc &quot; error: &quot; hr &quot;`nErrorLevel: &quot; ErrorLevel)
}

IDXGIOutput_GetDesc(this, pDesc)
{
   hr := DllCall(NumGet(NumGet(this+0)+7*A_PtrSize), &quot;ptr&quot;, this, &quot;ptr&quot;, pDesc)
   if hr or ErrorLevel
      _Error(A_ThisFunc &quot; error: &quot; hr &quot;`nErrorLevel: &quot; ErrorLevel)
}

IDXGIOutputDuplication_GetDesc(this, pDesc)
{
   DllCall(NumGet(NumGet(this+0)+7*A_PtrSize), &quot;ptr&quot;, this, &quot;ptr&quot;, pDesc)
   if ErrorLevel
      _Error(A_ThisFunc &quot; error: &quot; hr &quot;`nErrorLevel: &quot; ErrorLevel)
}

IDXGIOutputDuplication_AcquireNextFrame(this, TimeoutInMilliseconds, pFrameInfo, ByRef ppDesktopResource)
{
   hr := DllCall(NumGet(NumGet(this+0)+8*A_PtrSize), &quot;ptr&quot;, this, &quot;uint&quot;, TimeoutInMilliseconds, &quot;ptr&quot;, pFrameInfo, &quot;ptr*&quot;, ppDesktopResource)
   if hr or ErrorLevel
   {
      if (hr&amp;=0xFFFFFFFF) = 0x887A0027   ; DXGI_ERROR_WAIT_TIMEOUT
         return &quot;DXGI_ERROR_WAIT_TIMEOUT&quot;
      _Error(A_ThisFunc &quot; error: &quot; hr &quot;`nErrorLevel: &quot; ErrorLevel)
   }
}

D3D11CreateDevice(pAdapter, DriverType, Software, Flags, pFeatureLevels, FeatureLevels, SDKVersion, ByRef ppDevice, ByRef pFeatureLevel, ByRef ppImmediateContext)
{
   hr := DllCall(&quot;D3D11\D3D11CreateDevice&quot;, &quot;ptr&quot;, pAdapter, &quot;int&quot;, DriverType, &quot;ptr&quot;, Software, &quot;uint&quot;, Flags, &quot;ptr&quot;, pFeatureLevels, &quot;uint&quot;, FeatureLevels, &quot;uint&quot;, SDKVersion, &quot;ptr*&quot;, ppDevice, &quot;ptr*&quot;, pFeatureLevel, &quot;ptr*&quot;, ppImmediateContext)
   if hr or ErrorLevel
      _Error(A_ThisFunc &quot; error: &quot; hr &quot;`nErrorLevel: &quot; ErrorLevel)
}

ID3D11Device_CreateTexture2D(this, pDesc, pInitialData, ByRef ppTexture2D)
{
   hr := DllCall(NumGet(NumGet(this+0)+5*A_PtrSize), &quot;ptr&quot;, this, &quot;ptr&quot;, pDesc, &quot;ptr&quot;, pInitialData, &quot;ptr*&quot;, ppTexture2D)
   if hr or ErrorLevel
      _Error(A_ThisFunc &quot; error: &quot; hr &quot;`nErrorLevel: &quot; ErrorLevel)
}

IDXGIOutputDuplication_MapDesktopSurface(this, pLockedRect)
{
   hr := DllCall(NumGet(NumGet(this+0)+12*A_PtrSize), &quot;ptr&quot;, this, &quot;ptr&quot;, pLockedRect)
   if hr or ErrorLevel
   {
      if (hr&amp;=0xFFFFFFFF) = 0x887A0004   ; DXGI_ERROR_UNSUPPORTED
         return &quot;DXGI_ERROR_UNSUPPORTED&quot;
      _Error(A_ThisFunc &quot; error: &quot; hr &quot;`nErrorLevel: &quot; ErrorLevel)
   }
}

IDXGIOutputDuplication_UnMapDesktopSurface(this)
{
   hr := DllCall(NumGet(NumGet(this+0)+13*A_PtrSize), &quot;ptr&quot;, this)
   if hr or ErrorLevel
      _Error(A_ThisFunc &quot; error: &quot; hr &quot;`nErrorLevel: &quot; ErrorLevel)
}

IDXGIOutputDuplication_ReleaseFrame(this)
{
   hr := DllCall(NumGet(NumGet(this+0)+14*A_PtrSize), &quot;ptr&quot;, this)
   if hr or ErrorLevel
      _Error(A_ThisFunc &quot; error: &quot; hr &quot;`nErrorLevel: &quot; ErrorLevel)
}

IDXGIOutput1_DuplicateOutput(this, pDevice, ByRef ppOutputDuplication)
{
   hr := DllCall(NumGet(NumGet(this+0)+22*A_PtrSize), &quot;ptr&quot;, this, &quot;ptr&quot;, pDevice, &quot;ptr*&quot;, ppOutputDuplication)
   if hr or ErrorLevel
      _Error(A_ThisFunc &quot; error: &quot; hr &quot;`nErrorLevel: &quot; ErrorLevel)
}

IDXGIOutput1_Query(IDXGIOutput)
{ 
   hr := ComObjQuery(IDXGIOutput, &quot;{00cddea8-939b-4b83-a340-a685226666cc}&quot;)
   if !hr or ErrorLevel
      _Error(A_ThisFunc &quot; error: &quot; hr &quot;`nErrorLevel: &quot; ErrorLevel)
   return hr
}

ID3D11Texture2D_Query(desktop_resource)
{ 
   hr := ComObjQuery(desktop_resource, &quot;{6f15aaf2-d208-4e89-9ab4-489535d34f9c}&quot;)
   if !hr or ErrorLevel
      _Error(A_ThisFunc &quot; error: &quot; hr &quot;`nErrorLevel: &quot; ErrorLevel)
   return hr
}

ID3D11DeviceContext_CopyResource(this, pDstResource, pSrcResource)
{
   hr := DllCall(NumGet(NumGet(this+0)+47*A_PtrSize), &quot;ptr&quot;, this, &quot;ptr&quot;, pDstResource, &quot;ptr&quot;, pSrcResource)
   if ErrorLevel
      _Error(A_ThisFunc &quot; error: &quot; hr &quot;`nErrorLevel: &quot; ErrorLevel)
}

ID3D11DeviceContext_CopySubresourceRegion(this, pDstResource, DstSubresource, DstX, DstY, DstZ, pSrcResource, SrcSubresource, pSrcBox)
{
   hr := DllCall(NumGet(NumGet(this+0)+46*A_PtrSize), &quot;ptr&quot;, this, &quot;ptr&quot;, pDstResource, &quot;uint&quot;, DstSubresource, &quot;uint&quot;, DstX, &quot;uint&quot;, DstY, &quot;uint&quot;, DstZ, &quot;ptr&quot;, pSrcResource, &quot;uint&quot;, SrcSubresource, &quot;ptr&quot;, pSrcBox)
   if ErrorLevel
      _Error(A_ThisFunc &quot; error: &quot; hr &quot;`nErrorLevel: &quot; ErrorLevel)
}

ID3D11DeviceContext_Map(this, pResource, Subresource, MapType, MapFlags, pMappedResource)
{
   hr := DllCall(NumGet(NumGet(this+0)+14*A_PtrSize), &quot;ptr&quot;, this, &quot;ptr&quot;, pResource, &quot;uint&quot;, Subresource, &quot;uint&quot;, MapType, &quot;uint&quot;, MapFlags, &quot;ptr&quot;, pMappedResource)
   if hr or ErrorLevel
      _Error(A_ThisFunc &quot; error: &quot; hr &quot;`nErrorLevel: &quot; ErrorLevel)
}

ID3D11DeviceContext_Unmap(this, pResource, Subresource)
{
   hr := DllCall(NumGet(NumGet(this+0)+15*A_PtrSize), &quot;ptr&quot;, this, &quot;ptr&quot;, pResource, &quot;uint&quot;, Subresource)
   if ErrorLevel
      _Error(A_ThisFunc &quot; error: &quot; hr &quot;`nErrorLevel: &quot; ErrorLevel)
}

Release(this)
{
   DllCall(NumGet(NumGet(this+0)+2*A_PtrSize), &quot;ptr&quot;, this)
   if ErrorLevel
      _Error(A_ThisFunc &quot; error: &quot; hr &quot;`nErrorLevel: &quot; ErrorLevel)
}

GUID(ByRef GUID, sGUID)
{
    VarSetCapacity(GUID, 16, 0)
    return DllCall(&quot;ole32\CLSIDFromString&quot;, &quot;WStr&quot;, sGUID, &quot;Ptr&quot;, &amp;GUID) &gt;= 0 ? &amp;GUID : &quot;&quot;
}

_Error(val)
{
   msgbox % val
   ExitApp
}</code></pre></div><p><a href="http://forum.script-coding.com/viewtopic.php?id=15664">Тема для обсуждения</a></p>]]></description>
			<author><![CDATA[null@example.com (Malcev)]]></author>
			<pubDate>Sun, 12 Mar 2023 14:57:00 +0000</pubDate>
			<guid>http://forum.script-coding.com/viewtopic.php?pid=157117#p157117</guid>
		</item>
	</channel>
</rss>
