Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 55 additions & 26 deletions hal/dx12/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@ type AdapterCapabilities struct {

// SupportsROVs indicates rasterizer ordered views support.
SupportsROVs bool

// 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.
Expand Down Expand Up @@ -91,6 +98,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()

Expand Down Expand Up @@ -158,6 +168,27 @@ 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 {
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.
func (a *Adapter) setTextureLimits() {
// D3D12 limits based on feature level
Expand Down Expand Up @@ -274,32 +305,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.
Expand Down Expand Up @@ -502,6 +520,23 @@ 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 {
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()

Expand Down Expand Up @@ -581,21 +616,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.
Expand Down
8 changes: 8 additions & 0 deletions hal/dx12/d3d12/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading