diff --git a/lib/gfx/depth_peek.cpp b/lib/gfx/depth_peek.cpp index 8ba493c..3fe72cb 100644 --- a/lib/gfx/depth_peek.cpp +++ b/lib/gfx/depth_peek.cpp @@ -71,6 +71,7 @@ struct PendingMap { uint64_t byteSize = 0; }; +bool g_enabled = false; std::array g_slots; size_t g_nextSlot = 0; wgpu::BindGroupLayout g_bindGroupLayout; @@ -305,8 +306,12 @@ void complete_slot(size_t slotIdx, wgpu::MapAsyncStatus status, wgpu::StringView } // namespace void initialize() { + if (!webgpu::g_hasCoreCompatibility) { + return; + } g_bindGroupLayout = create_bind_group_layout("Depth Peek Bind Group Layout"); g_pipeline = create_pipeline(g_bindGroupLayout, "Depth Peek Pipeline"); + g_enabled = true; } void shutdown() { @@ -319,6 +324,9 @@ void shutdown() { } void request_snapshot() noexcept { + if (!g_enabled) { + return; + } std::lock_guard lock{g_mutex}; g_snapshotRequested = true; } @@ -334,6 +342,10 @@ bool read_latest(uint16_t x, uint16_t y, uint32_t& z) noexcept { void encode_frame_snapshot(const wgpu::CommandEncoder& cmd, const wgpu::TextureView& depthView, wgpu::Extent3D sourceSize, uint32_t msaaSamples) noexcept { + if (!g_enabled) { + return; + } + ZoneScoped; const auto now = Clock::now(); { @@ -413,6 +425,10 @@ void encode_frame_snapshot(const wgpu::CommandEncoder& cmd, const wgpu::TextureV } void after_submit() noexcept { + if (!g_enabled) { + return; + } + std::vector pendingMaps; { std::lock_guard lock{g_mutex}; diff --git a/lib/gfx/tex_copy_conv.cpp b/lib/gfx/tex_copy_conv.cpp index 56187c9..bf7c67c 100644 --- a/lib/gfx/tex_copy_conv.cpp +++ b/lib/gfx/tex_copy_conv.cpp @@ -400,10 +400,13 @@ void initialize() { Log.fatal("Output format mismatch for {}", conv.fmt); } } - for (const auto& conv : DepthConvPipelines) { - g_pipelines[conv.fmt] = create_pipeline(conv, DepthShaderPreamble, g_depthBindGroupLayout); - if (conv.outputFormat != to_wgpu(conv.fmt)) { - Log.fatal("Output format mismatch for {}", conv.fmt); + // Skip depth copies in compatibility mode + if (webgpu::g_hasCoreCompatibility) { + for (const auto& conv : DepthConvPipelines) { + g_pipelines[conv.fmt] = create_pipeline(conv, DepthShaderPreamble, g_depthBindGroupLayout); + if (conv.outputFormat != to_wgpu(conv.fmt)) { + Log.fatal("Output format mismatch for {}", conv.fmt); + } } } @@ -432,8 +435,15 @@ void shutdown() { } static void execute(const wgpu::CommandEncoder& cmd, const ConvRequest& req, const wgpu::RenderPipeline& pipeline) { + if (!pipeline) { + return; + } wgpu::BindGroup bindGroup; if (gx::is_depth_format(req.fmt)) { + // Skip depth copies in compatibility mode + if (!webgpu::g_hasCoreCompatibility) { + return; + } const std::array bindGroupEntries{ wgpu::BindGroupEntry{ .binding = 0, diff --git a/lib/gx/gx.cpp b/lib/gx/gx.cpp index 2458a5f..5aa1467 100644 --- a/lib/gx/gx.cpp +++ b/lib/gx/gx.cpp @@ -635,13 +635,16 @@ wgpu::RenderPipeline build_pipeline(const PipelineConfig& config, ArrayRef(config.polygonOffsetBits); const float depthBiasSlopeScale = (UseReversedZ ? -1.0f : 1.0f) * std::bit_cast(config.polygonOffsetScaleBits); + const float depthBiasClamp = webgpu::g_hasCoreCompatibility + ? std::bit_cast(config.polygonOffsetClampBits) + : 0.0f; const wgpu::DepthStencilState depthStencil{ .format = g_graphicsConfig.depthFormat, .depthWriteEnabled = config.depthCompare && config.depthUpdate, .depthCompare = config.depthCompare ? to_compare_function(config.depthFunc) : wgpu::CompareFunction::Always, .depthBias = round_away_from_zero(depthBias), .depthBiasSlopeScale = depthBiasSlopeScale, - .depthBiasClamp = std::bit_cast(config.polygonOffsetClampBits), + .depthBiasClamp = depthBiasClamp, }; const auto blendState = to_blend_state(config.blendMode, config.blendFacSrc, config.blendFacDst, config.blendOp, config.dstAlpha); diff --git a/lib/webgpu/gpu.cpp b/lib/webgpu/gpu.cpp index 0c747b2..bc50440 100644 --- a/lib/webgpu/gpu.cpp +++ b/lib/webgpu/gpu.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -59,6 +60,7 @@ static wgpu::Adapter g_adapter; wgpu::Instance g_instance; wgpu::AdapterInfo g_adapterInfo; static wgpu::SurfaceCapabilities g_surfaceCapabilities; +bool g_hasCoreCompatibility = false; bool g_bcTexturesSupported = false; bool g_astcTexturesSupported = false; bool g_textureComponentSwizzleSupported = false; @@ -66,6 +68,25 @@ static std::atomic_bool g_initialized = false; namespace { +AuroraLogLevel wgpu_log_level(wgpu::LoggingType type) { + switch (type) { + case wgpu::LoggingType::Verbose: + return LOG_DEBUG; + case wgpu::LoggingType::Info: + return LOG_INFO; + case wgpu::LoggingType::Warning: + return LOG_WARNING; + case wgpu::LoggingType::Error: + return LOG_ERROR; + default: + return LOG_FATAL; + } +} + +void wgpu_log(wgpu::LoggingType type, wgpu::StringView message) { + Log.report(wgpu_log_level(type), "WebGPU message: {}", message); +} + struct ResampleUniformBlock { uint32_t samplerMode = 0; float frameWidth = 0.f; @@ -742,6 +763,7 @@ bool initialize(AuroraBackend auroraBackend, bool allowCpu) { #ifdef WEBGPU_DAWN dawn::native::DawnInstanceDescriptor dawnInstanceDescriptor; dawnInstanceDescriptor.backendValidationLevel = dawn::native::BackendValidationLevel::Disabled; + dawnInstanceDescriptor.SetLoggingCallback(wgpu_log); #ifdef TRACY_ENABLE dawnInstanceDescriptor.platform = tracy_dawn_platform(); #endif @@ -765,26 +787,47 @@ bool initialize(AuroraBackend auroraBackend, bool allowCpu) { } { const wgpu::RequestAdapterOptions options{ + .featureLevel = wgpu::FeatureLevel::Compatibility, .powerPreference = wgpu::PowerPreference::HighPerformance, .backendType = backend, .compatibleSurface = g_surface, }; + Log.info("Requesting adapter\n Feature level: {}\n Power preference: {}\n Backend: {}\n Compatible surface: {}", + magic_enum::enum_name(options.featureLevel), magic_enum::enum_name(options.powerPreference), + magic_enum::enum_name(options.backendType), static_cast(options.compatibleSurface)); + bool requestAdapterCallbackCompleted = false; + wgpu::RequestAdapterStatus requestAdapterStatus = wgpu::RequestAdapterStatus::CallbackCancelled; + std::string requestAdapterMessage; const auto future = g_instance.RequestAdapter( &options, wgpu::CallbackMode::WaitAnyOnly, - [](wgpu::RequestAdapterStatus status, wgpu::Adapter adapter, wgpu::StringView message) { + [&](wgpu::RequestAdapterStatus status, wgpu::Adapter adapter, wgpu::StringView message) { + requestAdapterCallbackCompleted = true; + requestAdapterStatus = status; + requestAdapterMessage = std::string{std::string_view{message}}; if (status == wgpu::RequestAdapterStatus::Success) { g_adapter = std::move(adapter); } else { - Log.warn("Adapter request failed: {}", message); + Log.warn("Adapter request failed: {}: {}", magic_enum::enum_name(status), message); } }); const auto status = g_instance.WaitAny(future, 5000000000); if (status != wgpu::WaitStatus::Success) { - Log.error("Failed to create adapter: {}", magic_enum::enum_name(status)); + if (requestAdapterCallbackCompleted) { + Log.error("Failed to create adapter: wait status {}, request status {}, message: {}", + magic_enum::enum_name(status), magic_enum::enum_name(requestAdapterStatus), requestAdapterMessage); + } else { + Log.error("Failed to create adapter: wait status {}, request callback did not complete", + magic_enum::enum_name(status)); + } return false; } if (!g_adapter) { - Log.error("Failed to create adapter"); + if (requestAdapterCallbackCompleted) { + Log.error("Failed to create adapter: request status {}, message: {}", + magic_enum::enum_name(requestAdapterStatus), requestAdapterMessage); + } else { + Log.error("Failed to create adapter: request callback did not complete"); + } return false; } } @@ -811,7 +854,12 @@ bool initialize(AuroraBackend auroraBackend, bool allowCpu) { { wgpu::Limits supportedLimits{}; g_adapter.GetLimits(&supportedLimits); + wgpu::CompatibilityModeLimits compatibilityModeLimits{wgpu::CompatibilityModeLimits::Init{ + .maxStorageBuffersInVertexStage = 2, + .maxStorageBuffersInFragmentStage = 2, + }}; const wgpu::Limits requiredLimits{ + .nextInChain = &compatibilityModeLimits, // Use "best" supported limits .maxTextureDimension1D = supportedLimits.maxTextureDimension1D == 0 ? WGPU_LIMIT_U32_UNDEFINED : supportedLimits.maxTextureDimension1D, @@ -821,12 +869,7 @@ bool initialize(AuroraBackend auroraBackend, bool allowCpu) { : supportedLimits.maxTextureDimension3D, .maxTextureArrayLayers = supportedLimits.maxTextureArrayLayers == 0 ? WGPU_LIMIT_U32_UNDEFINED : supportedLimits.maxTextureArrayLayers, - .maxDynamicStorageBuffersPerPipelineLayout = supportedLimits.maxDynamicStorageBuffersPerPipelineLayout == 0 - ? WGPU_LIMIT_U32_UNDEFINED - : supportedLimits.maxDynamicStorageBuffersPerPipelineLayout, - .maxStorageBuffersPerShaderStage = supportedLimits.maxStorageBuffersPerShaderStage == 0 - ? WGPU_LIMIT_U32_UNDEFINED - : supportedLimits.maxStorageBuffersPerShaderStage, + .maxStorageBuffersPerShaderStage = 2, .minUniformBufferOffsetAlignment = supportedLimits.minUniformBufferOffsetAlignment < 64 ? 64 : supportedLimits.minUniformBufferOffsetAlignment, .minStorageBufferOffsetAlignment = @@ -838,15 +881,15 @@ bool initialize(AuroraBackend auroraBackend, bool allowCpu) { "\n maxTextureDimension2D: {}" "\n maxTextureDimension3D: {}" "\n maxTextureArrayLayers: {}" - "\n maxDynamicStorageBuffersPerPipelineLayout: {}" "\n maxStorageBuffersPerShaderStage: {}" "\n minUniformBufferOffsetAlignment: {}" "\n minStorageBufferOffsetAlignment: {}", requiredLimits.maxTextureDimension1D, requiredLimits.maxTextureDimension2D, requiredLimits.maxTextureDimension3D, requiredLimits.maxTextureArrayLayers, - requiredLimits.maxDynamicStorageBuffersPerPipelineLayout, requiredLimits.maxStorageBuffersPerShaderStage, - requiredLimits.minUniformBufferOffsetAlignment, requiredLimits.minStorageBufferOffsetAlignment); + requiredLimits.maxStorageBuffersPerShaderStage, requiredLimits.minUniformBufferOffsetAlignment, + requiredLimits.minStorageBufferOffsetAlignment); std::vector requiredFeatures; + g_hasCoreCompatibility = false; g_bcTexturesSupported = false; g_astcTexturesSupported = false; g_textureComponentSwizzleSupported = false; @@ -854,9 +897,12 @@ bool initialize(AuroraBackend auroraBackend, bool allowCpu) { g_adapter.GetFeatures(&supportedFeatures); for (size_t i = 0; i < supportedFeatures.featureCount; ++i) { const auto feature = supportedFeatures.features[i]; - if (feature == wgpu::FeatureName::TextureCompressionBC || feature == wgpu::FeatureName::TextureCompressionASTC || + if (feature == wgpu::FeatureName::CoreFeaturesAndLimits || feature == wgpu::FeatureName::TextureCompressionBC || + feature == wgpu::FeatureName::TextureCompressionASTC || feature == wgpu::FeatureName::TextureComponentSwizzle) { - if (feature == wgpu::FeatureName::TextureCompressionBC) { + if (feature == wgpu::FeatureName::CoreFeaturesAndLimits) { + g_hasCoreCompatibility = true; + } else if (feature == wgpu::FeatureName::TextureCompressionBC) { g_bcTexturesSupported = true; } else if (feature == wgpu::FeatureName::TextureCompressionASTC) { g_astcTexturesSupported = true; @@ -871,6 +917,12 @@ bool initialize(AuroraBackend auroraBackend, bool allowCpu) { } #endif } + std::string featureList; + for (auto featureName : requiredFeatures) { + featureList += "\n "; + featureList += magic_enum::enum_name(featureName); + } + Log.info("Enabling features: {}", featureList); #ifdef WEBGPU_DAWN wgpu::DawnCacheDeviceDescriptor cacheDescriptor({ .isolationKey = nullptr, @@ -896,6 +948,7 @@ bool initialize(AuroraBackend auroraBackend, bool allowCpu) { "allow_unsafe_apis", "disable_symbol_renaming", "enable_immediate_error_handling", + "gl_allow_context_on_multi_threads", }; constexpr std::array disableToggles{ "timestamp_quantization", @@ -950,26 +1003,7 @@ bool initialize(AuroraBackend auroraBackend, bool allowCpu) { if (!g_device) { return false; } - g_device.SetLoggingCallback([](wgpu::LoggingType type, wgpu::StringView message) { - AuroraLogLevel level = LOG_FATAL; - switch (type) { - case wgpu::LoggingType::Verbose: - level = LOG_DEBUG; - break; - case wgpu::LoggingType::Info: - level = LOG_INFO; - break; - case wgpu::LoggingType::Warning: - level = LOG_WARNING; - break; - case wgpu::LoggingType::Error: - level = LOG_ERROR; - break; - default: - break; - } - Log.report(level, "WebGPU message: {}", message); - }); + g_device.SetLoggingCallback(wgpu_log); } g_queue = g_device.GetQueue(); diff --git a/lib/webgpu/gpu.hpp b/lib/webgpu/gpu.hpp index 0753052..78146e9 100644 --- a/lib/webgpu/gpu.hpp +++ b/lib/webgpu/gpu.hpp @@ -52,6 +52,7 @@ extern wgpu::RenderPipeline g_CopyPremultipliedAlphaPipeline; extern wgpu::BindGroup g_CopyBindGroup; extern wgpu::Instance g_instance; extern wgpu::AdapterInfo g_adapterInfo; +extern bool g_hasCoreCompatibility; extern bool g_bcTexturesSupported; extern bool g_astcTexturesSupported; extern bool g_textureComponentSwizzleSupported;