diff --git a/generator/dawn_gpu_info_generator.py b/generator/dawn_gpu_info_generator.py index 31b1eb5e62..c059afbfd7 100644 --- a/generator/dawn_gpu_info_generator.py +++ b/generator/dawn_gpu_info_generator.py @@ -19,6 +19,12 @@ from collections import namedtuple from generator_lib import Generator, run_generator, FileRender +def parse_mask(mask): + if mask: + return int(mask, 0) + return 0xffffffff + + class Name: def __init__(self, name): self.name = name @@ -59,45 +65,136 @@ class Name: class Architecture: - def __init__(self, name, json_data): + def __init__(self, name, json_data, mask): self.name = Name(name) self.devices = [] + + mask_num = parse_mask(mask) + for device in json_data: + device_num = int(device, 0) + + # Don't allow duplicate entries + assert device not in self.devices, 'Architecture "{}" contained duplicate deviceID "{}"'.format( + self.name.get(), device) + # Ensure that all device IDs don't contain bits outside the mask + assert device_num & mask_num == device_num, 'Architecture "{}" contained deviceID "{}" which doesn\'t match the given mask of "{}"'.format( + self.name.get(), device, mask) + self.devices.append(device) +class DeviceSet: + def __init__(self, json_data): + self.mask = None + self.internal = False + + if 'mask' in json_data: + self.mask = json_data['mask'] + + if 'internal' in json_data: + self.internal = json_data['internal'] + + self.architectures = [] + if 'architecture' in json_data: + for (arch_name, arch_data) in json_data['architecture'].items(): + # Skip any entries that start with an underscore. Used for comments. + if arch_name[0] == '_': + continue + + architecture = Architecture(arch_name, arch_data, self.mask) + + # Validate that deviceIDs are only allowed to be in one Architecture at a time + for other_architecture in self.architectures: + for device in architecture.devices: + assert device not in other_architecture.devices, 'Architectures "{}" and "{}" both contain deviceID "{}"'.format( + architecture.name.get(), + other_architecture.name.get(), device) + + self.architectures.append(architecture) + + def validate_devices(self, other_devices, other_mask): + combined_mask = parse_mask(self.mask) & parse_mask(other_mask) + + for other_device in other_devices: + other_device_num = int(other_device, 0) & combined_mask + for architecture in self.architectures: + for device in architecture.devices: + device_num = int(device, 0) & combined_mask + assert device_num != other_device_num, 'DeviceID "{}" & mask "{}" conflicts with deviceId "{}" & mask "{}" in architecture "{}"'.format( + other_device, other_mask, device, self.mask, + architecture.name.get()) + + def maskDeviceId(self): + if not self.mask: + return '' + return ' & ' + self.mask + + class Vendor: def __init__(self, name, json_data): self.name = Name(name) self.id = json_data['id'] - self.deviceMask = None - if 'deviceMask' in json_data: - self.deviceMask = json_data['deviceMask'] + architecture_dict = {} + internal_architecture_dict = {} - self.architectures = [] + self.device_sets = [] + if 'devices' in json_data: + for device_data in json_data['devices']: + device_set = DeviceSet(device_data) - if 'architecture' in json_data: - for (arch_name, arch_data) in json_data['architecture'].items(): - # Skip any entries that start with an underscore. Used for comments. - if arch_name[0] == '_': - continue + for architecture in device_set.architectures: - self.architectures.append(Architecture(arch_name, arch_data)) + # Validate that deviceIDs are unique across device sets + for other_device_set in self.device_sets: + # Only validate device IDs between internal and public device sets. + if other_device_set.internal == device_set.internal: + assert device_set.mask != other_device_set.mask, 'Vendor "{}" contained duplicate device masks "{}"'.format( + self.name.get(), device_set.mask) + other_device_set.validate_devices( + architecture.devices, device_set.mask) - def maskDeviceId(self): - if not self.deviceMask: - return '' - return ' & ' + self.deviceMask + # Validate that architecture names are unique between internal and public device sets. + else: + for other_architecture in other_device_set.architectures: + assert architecture.name.canonical_case( + ) != other_architecture.name.canonical_case( + ), '"{}" is defined as both an internal and public architecture'.format( + architecture.name.get()) + + if device_set.internal: + internal_architecture_dict[ + architecture.name.canonical_case( + )] = architecture.name + else: + architecture_dict[architecture.name.canonical_case( + )] = architecture.name + + self.device_sets.append(device_set) + + # List of unique architecture names under this vendor + self.architecture_names = architecture_dict.values() + self.internal_architecture_names = internal_architecture_dict.values() def parse_json(json): vendors = [] + internal_architecture_count = 0 - for (vendor, vendor_data) in json['vendors'].items(): - vendors.append(Vendor(vendor, vendor_data)) + for (vendor_name, vendor_data) in json['vendors'].items(): + # Skip vendors that have a leading underscore. Those are intended to be "comments". + if vendor_name[0] == '_': + continue - return {'vendors': vendors} + vendor = Vendor(vendor_name, vendor_data) + vendors.append(vendor) + internal_architecture_count += len(vendor.internal_architecture_names) + + return { + 'vendors': vendors, + 'has_internal': internal_architecture_count > 0 + } class DawnGpuInfoGenerator(Generator): diff --git a/generator/templates/dawn/common/GPUInfo.cpp b/generator/templates/dawn/common/GPUInfo.cpp index 49ea9a42cd..f24c26255f 100644 --- a/generator/templates/dawn/common/GPUInfo.cpp +++ b/generator/templates/dawn/common/GPUInfo.cpp @@ -28,8 +28,8 @@ namespace { enum class Architecture { Unknown, {% for vendor in vendors %} - {% for architecture in vendor.architectures %} - {{vendor.name.CamelCase()}}_{{architecture.name.CamelCase()}}, + {% for architecture_name in vendor.architecture_names %} + {{vendor.name.CamelCase()}}_{{architecture_name.CamelCase()}}, {% endfor %} {% endfor %} }; @@ -37,17 +37,20 @@ enum class Architecture { Architecture GetArchitecture(PCIVendorID vendorId, PCIDeviceID deviceId) { switch(vendorId) { {% for vendor in vendors %} - {% if len(vendor.architectures) %} - + {% if len(vendor.device_sets) %} case kVendorID_{{vendor.name.CamelCase()}}: { - switch (deviceId{{vendor.maskDeviceId()}}) { - {% for architecture in vendor.architectures %} - {% for device in architecture.devices %} - case {{device}}: - {% endfor %} - return Architecture::{{vendor.name.CamelCase()}}_{{architecture.name.CamelCase()}}; - {% endfor %} - } + {% for device_set in vendor.device_sets %} + {% if not device_set.internal %} + switch (deviceId{{device_set.maskDeviceId()}}) { + {% for architecture in device_set.architectures %} + {% for device in architecture.devices %} + case {{device}}: + {% endfor %} + return Architecture::{{vendor.name.CamelCase()}}_{{architecture.name.CamelCase()}}; + {% endfor %} + } + {% endif %} + {% endfor %} } break; {% endif %} {% endfor %} @@ -56,6 +59,44 @@ Architecture GetArchitecture(PCIVendorID vendorId, PCIDeviceID deviceId) { return Architecture::Unknown; } +{% if has_internal %} + + enum class InternalArchitecture { + Unknown, + {% for vendor in vendors %} + {% for architecture_name in vendor.internal_architecture_names %} + {{vendor.name.CamelCase()}}_{{architecture_name.CamelCase()}}, + {% endfor %} + {% endfor %} + }; + + InternalArchitecture GetInternalArchitecture(PCIVendorID vendorId, PCIDeviceID deviceId) { + switch(vendorId) { + {% for vendor in vendors %} + {% if len(vendor.device_sets) %} + case kVendorID_{{vendor.name.CamelCase()}}: { + {% for device_set in vendor.device_sets %} + {% if device_set.internal %} + switch (deviceId{{device_set.maskDeviceId()}}) { + {% for architecture in device_set.architectures %} + {% for device in architecture.devices %} + case {{device}}: + {% endfor %} + return InternalArchitecture::{{vendor.name.CamelCase()}}_{{architecture.name.CamelCase()}}; + {% endfor %} + } + {% endif %} + {% endfor %} + } break; + {% endif %} + {% endfor %} + } + + return InternalArchitecture::Unknown; + } + +{% endif %} + } // namespace // Vendor checks @@ -68,11 +109,16 @@ Architecture GetArchitecture(PCIVendorID vendorId, PCIDeviceID deviceId) { // Architecture checks {% for vendor in vendors %} - {% if len(vendor.architectures) %} + {% if len(vendor.architecture_names) %} // {{vendor.name.get()}} architectures - {% for architecture in vendor.architectures %} - bool Is{{vendor.name.CamelCase()}}{{architecture.name.CamelCase()}}(PCIVendorID vendorId, PCIDeviceID deviceId) { - return GetArchitecture(vendorId, deviceId) == Architecture::{{vendor.name.CamelCase()}}_{{architecture.name.CamelCase()}}; + {% for architecture_name in vendor.architecture_names %} + bool Is{{vendor.name.CamelCase()}}{{architecture_name.CamelCase()}}(PCIVendorID vendorId, PCIDeviceID deviceId) { + return GetArchitecture(vendorId, deviceId) == Architecture::{{vendor.name.CamelCase()}}_{{architecture_name.CamelCase()}}; + } + {% endfor %} + {% for architecture_name in vendor.internal_architecture_names %} + bool Is{{vendor.name.CamelCase()}}{{architecture_name.CamelCase()}}(PCIVendorID vendorId, PCIDeviceID deviceId) { + return GetInternalArchitecture(vendorId, deviceId) == InternalArchitecture::{{vendor.name.CamelCase()}}_{{architecture_name.CamelCase()}}; } {% endfor %} {% endif %} @@ -95,9 +141,9 @@ std::string GetArchitectureName(PCIVendorID vendorId, PCIDeviceID deviceId) { case Architecture::Unknown: return ""; {% for vendor in vendors %} - {% for architecture in vendor.architectures %} - case Architecture::{{vendor.name.CamelCase()}}_{{architecture.name.CamelCase()}}: - return "{{architecture.name.js_enum_case()}}"; + {% for architecture_name in vendor.architecture_names %} + case Architecture::{{vendor.name.CamelCase()}}_{{architecture_name.CamelCase()}}: + return "{{architecture_name.js_enum_case()}}"; {% endfor %} {% endfor %} } diff --git a/generator/templates/dawn/common/GPUInfo.h b/generator/templates/dawn/common/GPUInfo.h index f4a54e0a7a..f058008cd4 100644 --- a/generator/templates/dawn/common/GPUInfo.h +++ b/generator/templates/dawn/common/GPUInfo.h @@ -35,11 +35,14 @@ namespace gpu_info { // Architecture checks {% for vendor in vendors %} - {% if len(vendor.architectures) %} + {% if len(vendor.architecture_names) %} // {{vendor.name.get()}} architectures - {% for architecture in vendor.architectures %} - bool Is{{vendor.name.CamelCase()}}{{architecture.name.CamelCase()}}(PCIVendorID vendorId, PCIDeviceID deviceId); + {% for architecture_name in vendor.architecture_names %} + bool Is{{vendor.name.CamelCase()}}{{architecture_name.CamelCase()}}(PCIVendorID vendorId, PCIDeviceID deviceId); + {% endfor %} + {% for architecture_name in vendor.internal_architecture_names %} + bool Is{{vendor.name.CamelCase()}}{{architecture_name.CamelCase()}}(PCIVendorID vendorId, PCIDeviceID deviceId); {% endfor %} {% endif %} {% endfor %} diff --git a/src/dawn/gpu_info.json b/src/dawn/gpu_info.json index ca02f0f015..64643b4af7 100644 --- a/src/dawn/gpu_info.json +++ b/src/dawn/gpu_info.json @@ -17,19 +17,86 @@ "vendors": { + "_Example Vendor": { + "_comment": [ + "Each vendor must have an `id` field, which is it's PCI Vendor ID, and may optionally ", + "have a `devices` field which defines device -> architecture mappings which will be ", + "when populating the GPUAdapterInfo. Keys that begin with an `_` (like this one) denote ", + "commnents, and will be ignored by the parser." + ], + + "id": "0xDEAD", + + "devices": [{ + "_comment": [ + "The `devices` is an array of 'Device Sets', each of which contains an `architecture` ", + "object which defines an architecture name as a key followed by an array of ", + "PCI device IDs that map to that architecture. The architecture name is what will be ", + "reported to the GPUAdapterInfo, made lower-case and with spaces converted to hyphens." + ], + + "architecture": { + "Alpha": ["0x0A01", "0x0A02"], + "Beta": ["0x0B01", "0x0B02", "0x0B03"] + } + }, { + "_comment": [ + "A Device Set can also define a binary `mask`, which will be be applied to any device ", + "ID prior to comparison, making it easier to capture ranges of device IDs. ", + "Architectures may be duplicated between Device Sets as long as the device ID values ", + "Don't overlap." + ], + + "mask": "0xFF00", + "architecture": { + "Beta": ["0x1B00"], + "Gamma": ["0x0C00", "0x1C00"] + } + }, { + "_comment": [ + "Finally, Device Sets may be flagged as `internal`. Architectures defined in an ", + "internal device set will never be reported in the GPUAdapterInfo, but will generate ", + "appropriate helper functions in Dawn (such as `IsExampleVendorDelta()`) in order to ", + "aid in applying workarounds. Device IDs of internal device sets may overlap with ", + "ones defined in non-internal device sets, but architectures must be unique between ", + "internal and non-internal device sets.", + + "Internal architectures facilitate the (hopefully rare) cases where more targeted ", + "GPU identification is required by Dawn's implementation than is provided by the normal ", + "architecture groupings. When possible, however, using non-internal architectures ", + "should be preferred when applying workarounds." + ], + + "internal": true, + "mask": "0xFFF0", + "architecture": { + "Beta Rev 3": ["0x1B30"] + } + }] + }, + "AMD": { "id": "0x1002", - "deviceMask": "0xFFF0", - "architecture": { - "GCN 1": ["0x6600", "0x6610", "0x6660", "0x6790", "0x6800", "0x6810", "0x6820", "0x6830"], - "GCN 2": ["0x1300", "0x1310", "0x6640", "0x6650", "0x67A0", "0x67B0", "0x9830", "0x9850"], - "GCN 3": ["0x6900", "0x6920", "0x6930", "0x7300", "0x9870", "0x98E0"], - "GCN 4": ["0x67C0", "0x67D0", "0x67E0", "0x67F0", "0x6980", "0x6990"], - "GCN 5": ["0x15D0", "0x1630", "0x1640", "0x66A0", "0x6860", "0x6870", "0x6940", "0x69A0"], - "RDNA 1": ["0x7310", "0x7340", "0x7360"], - "RDNA 2": ["0x73A0", "0x73B0", "0x73D0", "0x73E0", "0x73F0", "0x7420", "0x7430"] - } + "devices": [{ + "mask": "0xFF00", + "architecture": { + "GCN 2": ["0x1300"], + "GCN 5": ["0x1500", "0x1600"], + "RDNA 2": ["0x7400"] + } + }, { + "mask": "0xFFF0", + "architecture": { + "GCN 1": ["0x6600", "0x6610", "0x6660", "0x6790", "0x6800", "0x6810", "0x6820", "0x6830"], + "GCN 2": ["0x6640", "0x6650", "0x67A0", "0x67B0", "0x9830", "0x9850"], + "GCN 3": ["0x6900", "0x6920", "0x6930", "0x7300", "0x9870", "0x98E0"], + "GCN 4": ["0x67C0", "0x67D0", "0x67E0", "0x67F0", "0x6980", "0x6990"], + "GCN 5": ["0x66A0", "0x6860", "0x6870", "0x6940", "0x69A0"], + "RDNA 1": ["0x7310", "0x7340", "0x7360"], + "RDNA 2": ["0x73A0", "0x73B0", "0x73D0", "0x73E0", "0x73F0"] + } + }] }, "Apple": { @@ -47,26 +114,30 @@ "ARM": { "id": "0x13B5", - "deviceMask": "0xF0000000", - "architecture": { - "_comment": [ - "The Midgard GPUs have device IDs like 0x07______ and 0x08______, but it's easiest to", - "mask those values out and simply check for the highest octet being zero, since that", - "distinguishes it from the other architectures." - ], + "devices": [{ + "mask": "0xF0000000", + "architecture": { + "_comment": [ + "The Midgard GPUs have device IDs like 0x07______ and 0x08______, but it's easiest to", + "mask those values out and simply check for the highest octet being zero, since that", + "distinguishes it from the other architectures." + ], - "Midgard": ["0x00000000"], - "Bifrost": ["0x60000000", "0x70000000"], - "Valhall": ["0x90000000", "0xA0000000"] - } + "Midgard": ["0x00000000"], + "Bifrost": ["0x60000000", "0x70000000"], + "Valhall": ["0x90000000", "0xA0000000"] + } + }] }, "Google": { "id": "0x1AE0", - "architecture": { - "Swiftshader": ["0xC0DE"] - } + "devices": [{ + "architecture": { + "Swiftshader": ["0xC0DE"] + } + }] }, "Img Tec": { @@ -76,15 +147,17 @@ "Intel": { "id": "0x8086", - "deviceMask": "0xFF00", - "architecture": { - "Gen 7": ["0x0100", "0x0400", "0x0A00", "0x0D00", "0x0F00"], - "Gen 8": ["0x1600", "0x2200"], - "Gen 9": ["0x1900", "0x3100", "0x3E00", "0x5A00", "0x5900", "0x9B00"], - "Gen 11": ["0x8A00"], - "Gen 12 LP": ["0x4600", "0x4C00", "0x4900", "0x9A00"], - "Gen 12 HP": ["0x4F00", "0x5600"] - } + "devices": [{ + "mask": "0xFF00", + "architecture": { + "Gen 7": ["0x0100", "0x0400", "0x0A00", "0x0D00", "0x0F00"], + "Gen 8": ["0x1600", "0x2200"], + "Gen 9": ["0x1900", "0x3100", "0x3E00", "0x5A00", "0x5900", "0x9B00"], + "Gen 11": ["0x8A00"], + "Gen 12 LP": ["0x4600", "0x4C00", "0x4900", "0x9A00"], + "Gen 12 HP": ["0x4F00", "0x5600"] + } + }] }, "Mesa": { @@ -94,43 +167,51 @@ "Microsoft": { "id": "0x1414", - "architecture": { - "WARP": ["0x8c"] - } + "devices": [{ + "architecture": { + "WARP": ["0x8c"] + } + }] }, "Nvidia": { "id": "0x10DE", - "deviceMask": "0xFF00", - "architecture": { - "Fermi": ["0x0D00"], - "Kepler": ["0x0F00", "0x1000", "0x1100", "0x1200"], - "Maxwell": ["0x1300", "0x1400", "0x1600", "0x1700"], - "Pascal": ["0x1500", "0x1B00", "0x1C00", "0x1D00"], - "Turing": ["0x1E00", "0x1F00", "0x2100"], - "Ampere": ["0x2200", "0x2400", "0x2500"] - } + "devices": [{ + "mask": "0xFF00", + "architecture": { + "Fermi": ["0x0D00"], + "Kepler": ["0x0F00", "0x1000", "0x1100", "0x1200"], + "Maxwell": ["0x1300", "0x1400", "0x1600", "0x1700"], + "Pascal": ["0x1500", "0x1B00", "0x1C00", "0x1D00"], + "Turing": ["0x1E00", "0x1F00", "0x2100"], + "Ampere": ["0x2200", "0x2400", "0x2500"] + } + }] }, "Qualcomm": { "id": "0x5143", - "deviceMask": "0xFF000000", - "architecture": { - "Adreno 4xx": ["0x04000000"], - "Adreno 5xx": ["0x05000000"], - "Adreno 6xx": ["0x06000000"], - "Adreno 7xx": ["0x07000000"] - } + "devices": [{ + "mask": "0xFF000000", + "architecture": { + "Adreno 4xx": ["0x04000000"], + "Adreno 5xx": ["0x05000000"], + "Adreno 6xx": ["0x06000000"], + "Adreno 7xx": ["0x07000000"] + } + }] }, "Samsung": { "id": "0x144d", - "architecture": { - "RDNA 2": ["0x73A0"] - } + "devices": [{ + "architecture": { + "RDNA 2": ["0x73A0"] + } + }] } }