// Copyright 2025 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 <vector>

#include "src/dawn/common/GPUInfo.h"
#include "src/dawn/tests/DawnTest.h"

// The purpose of these tests is to prevent regressions of features and limits on architectures that
// are known to have these supported capabilities.
//
// Why? Because of the nature of feature/limit support in WebGPU we can easily accidentally drop
// (regress) optional capabilities for specific devices and dawn/CTS testing machinery and even
// external webgpu clients will respond gracefully. We (dawn) never want to silently regress
// features on critical platforms. If we are regressing it should be a deliberate decision which may
// involve changes to the tests below.
//
// How? Currently it is difficult to know our features/limit support for all hardware (could even be
// driver version dependent). So here we conservatively assert that specific architectures have
// specific features/limits.
//
// When? This file may need to be updated with new conservative tests if the CQ changes hardware or
// if we have deliberately chosen to regress specific features/limits on some devices.
//
// Not an official dawn/webgpu resource but this page can provide insights into features/limits:
// https://web3dsurvey.com/webgpu

namespace dawn {
namespace {

using FeatureArchInfoTestBase = DawnTestWithParams<>;

class FeatureArchInfoTest_MaxLimits : public FeatureArchInfoTestBase {
  protected:
    void GetRequiredLimits(const dawn::utils::ComboLimits& supported,
                           dawn::utils::ComboLimits& required) override {
        supported.UnlinkedCopyTo(&required);
    }
};

TEST_P(FeatureArchInfoTest_MaxLimits, SubgroupsSupported) {
    const bool subgroupSupportExpected =
        // All Apple Silicon
        gpu_info::IsApple(GetParam().adapterProperties.vendorID) ||
        // All Intel >Gen9 on Metal/Vulkan, and D3D12+DXC
        ((IsMetal() || IsVulkan() || IsDXC()) &&
         gpu_info::IsIntel(GetParam().adapterProperties.vendorID) &&
         !gpu_info::IsIntelGen9(GetParam().adapterProperties.vendorID,
                                GetParam().adapterProperties.deviceID));

    DAWN_TEST_UNSUPPORTED_IF(!subgroupSupportExpected);
    EXPECT_TRUE(this->SupportsFeatures({wgpu::FeatureName::Subgroups}));
}

TEST_P(FeatureArchInfoTest_MaxLimits, ShaderF16Supported) {
    // All apple silicon devices support f16
    const bool shaderF16SupportExpected = gpu_info::IsApple(GetParam().adapterProperties.vendorID);

    DAWN_TEST_UNSUPPORTED_IF(!shaderF16SupportExpected);
    EXPECT_TRUE(this->SupportsFeatures({wgpu::FeatureName::ShaderF16}));
}

TEST_P(FeatureArchInfoTest_MaxLimits, WorkgroupSizeMin1024Expected) {
    // All apple silicon devices are known to have 1k workgroup size limit.
    // This code will need to be changed if a new apple silicon device is released with a different
    // limit. Nvidia also support >= 1k workgroups.
    const bool isWorkgroupSizeGT1k = gpu_info::IsApple(GetParam().adapterProperties.vendorID) ||
                                     gpu_info::IsNvidia(GetParam().adapterProperties.vendorID);
    DAWN_TEST_UNSUPPORTED_IF(!isWorkgroupSizeGT1k);

    EXPECT_GE(GetSupportedLimits().maxComputeInvocationsPerWorkgroup, 1024u);
}

class FeatureArchInfoTest_TieredMaxLimits : public FeatureArchInfoTestBase {
  protected:
    bool GetRequireUseTieredLimits() override { return true; }
    void GetRequiredLimits(const dawn::utils::ComboLimits& supported,
                           dawn::utils::ComboLimits& required) override {
        supported.UnlinkedCopyTo(&required);
    }
};

TEST_P(FeatureArchInfoTest_TieredMaxLimits, D3DHighMaxVertexAttributes) {
    const bool isWindowsHighEnd =
        gpu_info::IsNvidia(GetParam().adapterProperties.vendorID) && (IsD3D11() || IsD3D12());
    DAWN_TEST_UNSUPPORTED_IF(!isWindowsHighEnd);

    // High-end windows desktop GPU should report at least 30 even when tiered is enabled
    // See crbug.com/430371785
    EXPECT_GE(GetSupportedLimits().maxVertexAttributes, 30u);
}

TEST_P(FeatureArchInfoTest_TieredMaxLimits, AppleMaxTextureDimension2D) {
    const bool isAppleSilicon = gpu_info::IsApple(GetParam().adapterProperties.vendorID);
    DAWN_TEST_UNSUPPORTED_IF(!isAppleSilicon);

    // Apple silicon should report > 16k. Most modern devices should support > 16k. Update this when
    // appropriate.
    EXPECT_GE(GetSupportedLimits().maxTextureDimension2D, 16384u);
}

TEST_P(FeatureArchInfoTest_TieredMaxLimits, MaxUniformBufferBindingSize) {
    // Swiftshader will return a lower limit than any modern device on CQ.
    DAWN_TEST_UNSUPPORTED_IF(IsSwiftshader() || IsANGLESwiftShader());
    EXPECT_EQ(GetSupportedLimits().maxUniformBufferBindingSize, 65536u);
}

TEST_P(FeatureArchInfoTest_MaxLimits, MinUniformBufferOffsetAlignment) {
    // All devices on CQ report 256. A value of 32 is commonplace on iOS (note the less than).
    EXPECT_LE(GetSupportedLimits().minUniformBufferOffsetAlignment, 256u);
}

TEST_P(FeatureArchInfoTest_TieredMaxLimits, D3DHighMaxDynamicUniformBuffersPerPipelineLayout) {
    const bool isWindowsHighEnd =
        gpu_info::IsNvidia(GetParam().adapterProperties.vendorID) && (IsD3D11() || IsD3D12());
    DAWN_TEST_UNSUPPORTED_IF(!isWindowsHighEnd);

    // High-end windows desktop GPU should report at least 10 even when tiered is enabled
    // See crbug.com/440381283
    EXPECT_GE(GetSupportedLimits().maxDynamicUniformBuffersPerPipelineLayout, 10u);
}

DAWN_INSTANTIATE_TEST(FeatureArchInfoTest_MaxLimits,
                      D3D11Backend(),
                      D3D12Backend(),
                      MetalBackend(),
                      OpenGLBackend(),
                      OpenGLESBackend(),
                      VulkanBackend(),
                      WebGPUBackend());

DAWN_INSTANTIATE_TEST(FeatureArchInfoTest_TieredMaxLimits,
                      D3D11Backend(),
                      D3D12Backend(),
                      MetalBackend(),
                      OpenGLBackend(),
                      OpenGLESBackend(),
                      VulkanBackend(),
                      WebGPUBackend());

}  // anonymous namespace
}  // namespace dawn
