| // Copyright 2023 The Dawn & Tint Authors |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are met: |
| // |
| // 1. Redistributions of source code must retain the above copyright notice, this |
| // list of conditions and the following disclaimer. |
| // |
| // 2. Redistributions in binary form must reproduce the above copyright notice, |
| // this list of conditions and the following disclaimer in the documentation |
| // and/or other materials provided with the distribution. |
| // |
| // 3. Neither the name of the copyright holder nor the names of its |
| // contributors may be used to endorse or promote products derived from |
| // this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE |
| // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
| // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| #include <algorithm> |
| #include <iomanip> |
| #include <iostream> |
| #include <memory> |
| #include <sstream> |
| #include <string> |
| #include <vector> |
| |
| #include "dawn/dawn_proc.h" // nogncheck |
| #include "dawn/native/DawnNative.h" |
| #include "dawn/webgpu_cpp_print.h" |
| |
| namespace { |
| |
| // Wraps a string to about 75 characters and prints indented. Splits on whitespace instead of |
| // between characters in a word. |
| std::string WrapString(const std::string& in, const std::string& indent) { |
| std::stringstream out; |
| |
| size_t last_space = 0; |
| size_t start_pos = 0; |
| for (size_t i = 0; i < in.size(); ++i) { |
| if (in[i] == ' ') { |
| last_space = i; |
| } else if (in[i] == '\n') { |
| last_space = i; |
| } |
| |
| if ((i - start_pos) != 0 && ((i - start_pos) % 75) == 0) { |
| out << indent << in.substr(start_pos, last_space - start_pos) << "\n"; |
| start_pos = last_space + 1; |
| last_space = start_pos; |
| } |
| } |
| out << indent << in.substr(start_pos, in.size() - start_pos); |
| |
| return out.str(); |
| } |
| |
| std::string AdapterTypeToString(wgpu::AdapterType type) { |
| switch (type) { |
| case wgpu::AdapterType::DiscreteGPU: |
| return "discrete GPU"; |
| case wgpu::AdapterType::IntegratedGPU: |
| return "integrated GPU"; |
| case wgpu::AdapterType::CPU: |
| return "CPU"; |
| case wgpu::AdapterType::Unknown: |
| break; |
| } |
| return "unknown"; |
| } |
| |
| std::string BackendTypeToString(wgpu::BackendType type) { |
| switch (type) { |
| case wgpu::BackendType::Null: |
| return "Null"; |
| case wgpu::BackendType::WebGPU: |
| return "WebGPU"; |
| case wgpu::BackendType::D3D11: |
| return "D3D11"; |
| case wgpu::BackendType::D3D12: |
| return "D3D12"; |
| case wgpu::BackendType::Metal: |
| return "Metal"; |
| case wgpu::BackendType::Vulkan: |
| return "Vulkan"; |
| case wgpu::BackendType::OpenGL: |
| return "OpenGL"; |
| case wgpu::BackendType::OpenGLES: |
| return "OpenGLES"; |
| case wgpu::BackendType::Undefined: |
| return "Undefined"; |
| } |
| return "unknown"; |
| } |
| |
| std::string PowerPreferenceToString(const wgpu::DawnAdapterPropertiesPowerPreference& prop) { |
| switch (prop.powerPreference) { |
| case wgpu::PowerPreference::LowPower: |
| return "low power"; |
| case wgpu::PowerPreference::HighPerformance: |
| return "high performance"; |
| case wgpu::PowerPreference::Undefined: |
| return "<undefined>"; |
| } |
| return "<unknown>"; |
| } |
| |
| std::string AsHex(uint32_t val) { |
| std::stringstream hex; |
| hex << "0x" << std::uppercase << std::setfill('0') << std::setw(4) << std::hex << val; |
| return hex.str(); |
| } |
| |
| std::string AdapterInfoToString(const wgpu::AdapterInfo& info) { |
| std::stringstream out; |
| out << "VendorID: " << AsHex(info.vendorID) << "\n"; |
| out << "Vendor: " << info.vendor << "\n"; |
| out << "Architecture: " << info.architecture << "\n"; |
| out << "DeviceID: " << AsHex(info.deviceID) << "\n"; |
| out << "Name: " << info.device << "\n"; |
| out << "Driver description: " << info.description << "\n"; |
| out << "Adapter Type: " << AdapterTypeToString(info.adapterType) << "\n"; |
| out << "Backend Type: " << BackendTypeToString(info.backendType) << "\n"; |
| |
| return out.str(); |
| } |
| |
| std::string FormatNumber(uint64_t num) { |
| auto s = std::to_string(num); |
| std::stringstream ret; |
| |
| auto remainder = s.length() % 3; |
| ret << s.substr(0, remainder); |
| for (size_t i = remainder; i < s.length(); i += 3) { |
| if (i > 0) { |
| ret << ","; |
| } |
| ret << s.substr(i, 3); |
| } |
| return ret.str(); |
| } |
| |
| std::string LimitsToString(const wgpu::Limits& limits, const std::string& indent) { |
| std::stringstream out; |
| |
| out << indent << "maxTextureDimension1D: " << FormatNumber(limits.maxTextureDimension1D) |
| << "\n"; |
| out << indent << "maxTextureDimension2D: " << FormatNumber(limits.maxTextureDimension2D) |
| << "\n"; |
| out << indent << "maxTextureDimension3D: " << FormatNumber(limits.maxTextureDimension3D) |
| << "\n"; |
| out << indent << "maxTextureArrayLayers: " << FormatNumber(limits.maxTextureArrayLayers) |
| << "\n"; |
| out << indent << "maxBindGroups: " << FormatNumber(limits.maxBindGroups) << "\n"; |
| out << indent |
| << "maxBindGroupsPlusVertexBuffers: " << FormatNumber(limits.maxBindGroupsPlusVertexBuffers) |
| << "\n"; |
| out << indent << "maxBindingsPerBindGroup: " << FormatNumber(limits.maxBindingsPerBindGroup) |
| << "\n"; |
| out << indent << "maxDynamicUniformBuffersPerPipelineLayout: " |
| << FormatNumber(limits.maxDynamicUniformBuffersPerPipelineLayout) << "\n"; |
| out << indent << "maxDynamicStorageBuffersPerPipelineLayout: " |
| << FormatNumber(limits.maxDynamicStorageBuffersPerPipelineLayout) << "\n"; |
| out << indent << "maxSampledTexturesPerShaderStage: " |
| << FormatNumber(limits.maxSampledTexturesPerShaderStage) << "\n"; |
| out << indent << "maxSamplersPerShaderStage: " << FormatNumber(limits.maxSamplersPerShaderStage) |
| << "\n"; |
| out << indent << "maxStorageBuffersPerShaderStage: " |
| << FormatNumber(limits.maxStorageBuffersPerShaderStage) << "\n"; |
| out << indent << "maxStorageTexturesPerShaderStage: " |
| << FormatNumber(limits.maxStorageTexturesPerShaderStage) << "\n"; |
| out << indent << "maxUniformBuffersPerShaderStage: " |
| << FormatNumber(limits.maxUniformBuffersPerShaderStage) << "\n"; |
| out << indent |
| << "maxUniformBufferBindingSize: " << FormatNumber(limits.maxUniformBufferBindingSize) |
| << "\n"; |
| out << indent |
| << "maxStorageBufferBindingSize: " << FormatNumber(limits.maxStorageBufferBindingSize) |
| << "\n"; |
| out << indent << "minUniformBufferOffsetAlignment: " |
| << FormatNumber(limits.minUniformBufferOffsetAlignment) << "\n"; |
| out << indent << "minStorageBufferOffsetAlignment: " |
| << FormatNumber(limits.minStorageBufferOffsetAlignment) << "\n"; |
| out << indent << "maxVertexBuffers: " << FormatNumber(limits.maxVertexBuffers) << "\n"; |
| out << indent << "maxBufferSize: " << FormatNumber(limits.maxBufferSize) << "\n"; |
| out << indent << "maxVertexAttributes: " << FormatNumber(limits.maxVertexAttributes) << "\n"; |
| out << indent |
| << "maxVertexBufferArrayStride: " << FormatNumber(limits.maxVertexBufferArrayStride) |
| << "\n"; |
| out << indent |
| << "maxInterStageShaderComponents: " << FormatNumber(limits.maxInterStageShaderComponents) |
| << "\n"; |
| out << indent |
| << "maxInterStageShaderVariables: " << FormatNumber(limits.maxInterStageShaderVariables) |
| << "\n"; |
| out << indent << "maxColorAttachments: " << FormatNumber(limits.maxColorAttachments) << "\n"; |
| out << indent << "maxColorAttachmentBytesPerSample: " |
| << FormatNumber(limits.maxColorAttachmentBytesPerSample) << "\n"; |
| out << indent |
| << "maxComputeWorkgroupStorageSize: " << FormatNumber(limits.maxComputeWorkgroupStorageSize) |
| << "\n"; |
| out << indent << "maxComputeInvocationsPerWorkgroup: " |
| << FormatNumber(limits.maxComputeInvocationsPerWorkgroup) << "\n"; |
| out << indent << "maxComputeWorkgroupSizeX: " << FormatNumber(limits.maxComputeWorkgroupSizeX) |
| << "\n"; |
| out << indent << "maxComputeWorkgroupSizeY: " << FormatNumber(limits.maxComputeWorkgroupSizeY) |
| << "\n"; |
| out << indent << "maxComputeWorkgroupSizeZ: " << FormatNumber(limits.maxComputeWorkgroupSizeZ) |
| << "\n"; |
| out << indent << "maxComputeWorkgroupsPerDimension: " |
| << FormatNumber(limits.maxComputeWorkgroupsPerDimension) << "\n"; |
| |
| return out.str(); |
| } |
| |
| void DumpAdapterInfo(const wgpu::Adapter& adapter) { |
| wgpu::DawnAdapterPropertiesPowerPreference power_props{}; |
| |
| wgpu::AdapterInfo info{}; |
| info.nextInChain = &power_props; |
| |
| adapter.GetInfo(&info); |
| std::cout << AdapterInfoToString(info); |
| std::cout << "Power: " << PowerPreferenceToString(power_props) << "\n"; |
| std::cout << "\n"; |
| } |
| |
| void DumpAdapterFeatures(const wgpu::Adapter& adapter) { |
| auto feature_count = adapter.EnumerateFeatures(nullptr); |
| std::vector<wgpu::FeatureName> features(feature_count); |
| adapter.EnumerateFeatures(features.data()); |
| |
| std::cout << " Features\n"; |
| std::cout << " ========\n"; |
| for (const auto& f : features) { |
| auto info = dawn::native::GetFeatureInfo(f); |
| std::cout << " * " << info->name << "\n"; |
| std::cout << WrapString(info->description, " ") << "\n"; |
| std::cout << " " << info->url << "\n"; |
| } |
| } |
| |
| void DumpAdapterLimits(const wgpu::Adapter& adapter) { |
| wgpu::SupportedLimits adapterLimits; |
| if (adapter.GetLimits(&adapterLimits)) { |
| std::cout << "\n"; |
| std::cout << " Adapter Limits\n"; |
| std::cout << " ==============\n"; |
| std::cout << LimitsToString(adapterLimits.limits, " ") << "\n"; |
| } |
| } |
| |
| void DumpAdapter(const wgpu::Adapter& adapter) { |
| std::cout << "Adapter\n"; |
| std::cout << "=======\n"; |
| |
| DumpAdapterInfo(adapter); |
| DumpAdapterFeatures(adapter); |
| DumpAdapterLimits(adapter); |
| } |
| |
| } // namespace |
| |
| int main(int argc, const char* argv[]) { |
| auto toggles = dawn::native::AllToggleInfos(); |
| std::sort(toggles.begin(), toggles.end(), [](const auto* a, const auto* b) { |
| return std::string(a->name) < std::string(b->name); |
| }); |
| |
| std::cout << "Toggles\n"; |
| std::cout << "=======\n"; |
| bool first = true; |
| for (const auto* info : toggles) { |
| if (!first) { |
| std::cout << "\n"; |
| } |
| first = false; |
| std::cout << " Name: " << info->name << "\n"; |
| std::cout << WrapString(info->description, " ") << "\n"; |
| std::cout << " " << info->url << "\n"; |
| } |
| std::cout << "\n"; |
| |
| dawnProcSetProcs(&dawn::native::GetProcs()); |
| |
| auto instance = std::make_unique<dawn::native::Instance>(); |
| std::vector<dawn::native::Adapter> adapters = instance->EnumerateAdapters(); |
| |
| for (const auto& adapter : adapters) { |
| DumpAdapter(wgpu::Adapter(adapter.Get())); |
| } |
| } |