From aee808b9bf11d33c0c4fb253470bb4b27e97aa99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D0=B5=D1=80=D0=B3=D0=B5=D0=B9=20=D0=AE=2E=20=D0=94?= =?UTF-8?q?=D0=B8=D0=BD=D0=B4=D0=B8=D0=BA=D0=BE=D0=B2?= Date: Mon, 13 Jul 2026 18:14:53 +0300 Subject: [PATCH 1/3] More correction of GPU classification as integrated/discrete type for DX12 --- hal/dx12/adapter.go | 63 ++++++++++++++++++++++++----------------- hal/dx12/d3d12/types.go | 8 ++++++ 2 files changed, 45 insertions(+), 26 deletions(-) diff --git a/hal/dx12/adapter.go b/hal/dx12/adapter.go index f7bae106..e7e3d468 100644 --- a/hal/dx12/adapter.go +++ b/hal/dx12/adapter.go @@ -54,6 +54,9 @@ type AdapterCapabilities struct { // SupportsROVs indicates rasterizer ordered views support. SupportsROVs bool + + // IsUMA indicates Unified Memory Architecture (integrated GPU). + IsUMA bool } // probeCapabilities probes the adapter's capabilities by creating a temporary device. @@ -91,6 +94,9 @@ func (a *Adapter) probeCapabilities() error { // Query D3D12 options a.queryD3D12Options(tempDevice) + // Query architecture (UMA) + a.queryArchitecture(tempDevice) + // Set default texture limits based on feature level a.setTextureLimits() @@ -158,6 +164,20 @@ func (a *Adapter) queryD3D12Options(device *d3d12.ID3D12Device) { ) } +// queryArchitecture queries the adapter's architecture (UMA). +func (a *Adapter) queryArchitecture(device *d3d12.ID3D12Device) { + var arch d3d12.D3D12_FEATURE_DATA_ARCHITECTURE + + err := device.CheckFeatureSupport( + d3d12.D3D12_FEATURE_ARCHITECTURE, + unsafe.Pointer(&arch), + uint32(unsafe.Sizeof(arch)), + ) + if err == nil && arch.UMA != 0 { + a.capabilities.IsUMA = true + } +} + // setTextureLimits sets texture dimension limits based on feature level. func (a *Adapter) setTextureLimits() { // D3D12 limits based on feature level @@ -274,32 +294,19 @@ func (a *Adapter) limits() gputypes.Limits { return limits } -// deviceType determines the device type from the adapter flags and dedicated memory. +// deviceType determines the device type from the adapter flags and UMA. func (a *Adapter) deviceType() gputypes.DeviceType { // Check for software adapter (WARP) if a.desc.Flags&dxgi.DXGI_ADAPTER_FLAG_SOFTWARE != 0 { return gputypes.DeviceTypeCPU } - // Check for dedicated video memory to distinguish discrete from integrated - if a.desc.DedicatedVideoMemory > 0 { - // Heuristic: >512MB dedicated VRAM is likely discrete - if a.desc.DedicatedVideoMemory > 512*1024*1024 { - return gputypes.DeviceTypeDiscreteGPU - } - } - - // If there's no dedicated video memory, it's likely integrated - if a.desc.DedicatedVideoMemory == 0 && a.desc.SharedSystemMemory > 0 { + // UMA means integrated GPU (shares system memory) + if a.capabilities.IsUMA { return gputypes.DeviceTypeIntegratedGPU } - // Assume discrete if there's any dedicated memory - if a.desc.DedicatedVideoMemory > 0 { - return gputypes.DeviceTypeDiscreteGPU - } - - return gputypes.DeviceTypeOther + return gputypes.DeviceTypeDiscreteGPU } // Open opens a logical device with the requested features and limits. @@ -502,6 +509,16 @@ func (a *AdapterLegacy) probeCapabilities() error { } defer tempDevice.Release() + // Query architecture (UMA) + var arch d3d12.D3D12_FEATURE_DATA_ARCHITECTURE + if err := tempDevice.CheckFeatureSupport( + d3d12.D3D12_FEATURE_ARCHITECTURE, + unsafe.Pointer(&arch), + uint32(unsafe.Sizeof(arch)), + ); err == nil && arch.UMA != 0 { + a.capabilities.IsUMA = true + } + // Set default texture limits based on feature level a.setTextureLimits() @@ -581,21 +598,15 @@ func (a *AdapterLegacy) Capabilities() hal.Capabilities { } } -// deviceType determines the device type from the adapter flags and dedicated memory. +// deviceType determines the device type from the adapter flags and UMA. func (a *AdapterLegacy) deviceType() gputypes.DeviceType { if a.desc.Flags&dxgi.DXGI_ADAPTER_FLAG_SOFTWARE != 0 { return gputypes.DeviceTypeCPU } - if a.desc.DedicatedVideoMemory > 512*1024*1024 { - return gputypes.DeviceTypeDiscreteGPU - } - if a.desc.DedicatedVideoMemory == 0 && a.desc.SharedSystemMemory > 0 { + if a.capabilities.IsUMA { return gputypes.DeviceTypeIntegratedGPU } - if a.desc.DedicatedVideoMemory > 0 { - return gputypes.DeviceTypeDiscreteGPU - } - return gputypes.DeviceTypeOther + return gputypes.DeviceTypeDiscreteGPU } // Open opens a logical device with the requested features and limits. diff --git a/hal/dx12/d3d12/types.go b/hal/dx12/d3d12/types.go index 3b2aa887..cec127b5 100644 --- a/hal/dx12/d3d12/types.go +++ b/hal/dx12/d3d12/types.go @@ -639,6 +639,14 @@ type D3D12_FEATURE_DATA_FEATURE_LEVELS struct { MaxSupportedFeatureLevel D3D_FEATURE_LEVEL } +// D3D12_FEATURE_DATA_ARCHITECTURE describes adapter architecture. +type D3D12_FEATURE_DATA_ARCHITECTURE struct { + NodeIndex uint32 + TileBasedRenderer int32 + UMA int32 + CacheCoherentUMA int32 +} + // D3D12_RENDER_PASS_RENDER_TARGET_DESC describes a render pass render target. type D3D12_RENDER_PASS_RENDER_TARGET_DESC struct { CPUDescriptor D3D12_CPU_DESCRIPTOR_HANDLE From 723e73e0e90d6b84b760c7c498ec71996bc9f578 Mon Sep 17 00:00:00 2001 From: Andrey Kolkov Date: Tue, 14 Jul 2026 13:58:48 +0300 Subject: [PATCH 2/3] feat(dx12): add CacheCoherentUMA + diagnostic logging MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Store IsCacheCoherentUMA from D3D12_FEATURE_DATA_ARCHITECTURE for future memory pool selection (D3D12_MEMORY_POOL_L0 vs L1). Add hal.Logger().Info() for architecture query — matches existing queryD3D12Options logging pattern. Both Adapter and AdapterLegacy. --- hal/dx12/adapter.go | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/hal/dx12/adapter.go b/hal/dx12/adapter.go index e7e3d468..de4b6fe2 100644 --- a/hal/dx12/adapter.go +++ b/hal/dx12/adapter.go @@ -57,6 +57,10 @@ type AdapterCapabilities struct { // IsUMA indicates Unified Memory Architecture (integrated GPU). IsUMA bool + + // IsCacheCoherentUMA indicates cache-coherent UMA (GPU snoops CPU cache). + // Used for memory pool selection: D3D12_MEMORY_POOL_L0 (UMA) vs L1 (non-UMA). + IsCacheCoherentUMA bool } // probeCapabilities probes the adapter's capabilities by creating a temporary device. @@ -173,9 +177,16 @@ func (a *Adapter) queryArchitecture(device *d3d12.ID3D12Device) { unsafe.Pointer(&arch), uint32(unsafe.Sizeof(arch)), ) - if err == nil && arch.UMA != 0 { - a.capabilities.IsUMA = true + if err == nil { + a.capabilities.IsUMA = arch.UMA != 0 + a.capabilities.IsCacheCoherentUMA = arch.CacheCoherentUMA != 0 } + + hal.Logger().Info("dx12: adapter architecture", + "uma", a.capabilities.IsUMA, + "cacheCoherentUMA", a.capabilities.IsCacheCoherentUMA, + "tileBasedRenderer", arch.TileBasedRenderer != 0, + ) } // setTextureLimits sets texture dimension limits based on feature level. @@ -515,10 +526,17 @@ func (a *AdapterLegacy) probeCapabilities() error { d3d12.D3D12_FEATURE_ARCHITECTURE, unsafe.Pointer(&arch), uint32(unsafe.Sizeof(arch)), - ); err == nil && arch.UMA != 0 { - a.capabilities.IsUMA = true + ); err == nil { + a.capabilities.IsUMA = arch.UMA != 0 + a.capabilities.IsCacheCoherentUMA = arch.CacheCoherentUMA != 0 } + hal.Logger().Info("dx12: legacy adapter architecture", + "uma", a.capabilities.IsUMA, + "cacheCoherentUMA", a.capabilities.IsCacheCoherentUMA, + "tileBasedRenderer", arch.TileBasedRenderer != 0, + ) + // Set default texture limits based on feature level a.setTextureLimits() From 9b22c85b096d5d94ecc7854c6ddaa8096ae9d4d9 Mon Sep 17 00:00:00 2001 From: Andrey Kolkov Date: Tue, 14 Jul 2026 14:04:54 +0300 Subject: [PATCH 3/3] style: gofmt types.go --- hal/dx12/d3d12/types.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hal/dx12/d3d12/types.go b/hal/dx12/d3d12/types.go index cec127b5..62055fb5 100644 --- a/hal/dx12/d3d12/types.go +++ b/hal/dx12/d3d12/types.go @@ -641,10 +641,10 @@ type D3D12_FEATURE_DATA_FEATURE_LEVELS struct { // D3D12_FEATURE_DATA_ARCHITECTURE describes adapter architecture. type D3D12_FEATURE_DATA_ARCHITECTURE struct { - NodeIndex uint32 - TileBasedRenderer int32 - UMA int32 - CacheCoherentUMA int32 + NodeIndex uint32 + TileBasedRenderer int32 + UMA int32 + CacheCoherentUMA int32 } // D3D12_RENDER_PASS_RENDER_TARGET_DESC describes a render pass render target.