// Copyright 2020 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <vector>

#include "dawn/common/Assert.h"
#include "dawn/tests/DawnTest.h"
#include "dawn/utils/ComboRenderPipelineDescriptor.h"
#include "dawn/utils/WGPUHelpers.h"

// Test that rendering to a subresource of a texture works.
class SubresourceRenderAttachmentTest : public DawnTest {
    constexpr static uint32_t kRTSize = 2;

  protected:
    enum class Type { Color, Depth, Stencil };

    void DoSingleTest(Type type,
                      wgpu::TextureFormat format,
                      wgpu::Texture renderTarget,
                      uint32_t textureSize,
                      uint32_t baseArrayLayer,
                      uint32_t baseMipLevel) {
        wgpu::TextureViewDescriptor renderTargetViewDesc;
        renderTargetViewDesc.baseArrayLayer = baseArrayLayer;
        renderTargetViewDesc.arrayLayerCount = 1;
        renderTargetViewDesc.baseMipLevel = baseMipLevel;
        renderTargetViewDesc.mipLevelCount = 1;
        wgpu::TextureView renderTargetView = renderTarget.CreateView(&renderTargetViewDesc);

        utils::RGBA8 expectedColor(0, 255, 0, 255);
        float expectedDepth = 0.3f;
        uint8_t expectedStencil = 7;

        utils::ComboRenderPassDescriptor renderPass = [&]() {
            switch (type) {
                case Type::Color: {
                    utils::ComboRenderPassDescriptor renderPass({renderTargetView});
                    renderPass.cColorAttachments[0].clearValue = {
                        static_cast<float>(expectedColor.r) / 255.f,
                        static_cast<float>(expectedColor.g) / 255.f,
                        static_cast<float>(expectedColor.b) / 255.f,
                        static_cast<float>(expectedColor.a) / 255.f,
                    };
                    return renderPass;
                }
                case Type::Depth: {
                    utils::ComboRenderPassDescriptor renderPass({}, renderTargetView);
                    renderPass.UnsetDepthStencilLoadStoreOpsForFormat(format);
                    renderPass.cDepthStencilAttachmentInfo.depthClearValue = expectedDepth;
                    return renderPass;
                }
                case Type::Stencil: {
                    utils::ComboRenderPassDescriptor renderPass({}, renderTargetView);
                    renderPass.UnsetDepthStencilLoadStoreOpsForFormat(format);
                    renderPass.cDepthStencilAttachmentInfo.stencilClearValue = expectedStencil;
                    return renderPass;
                }
                default:
                    UNREACHABLE();
            }
        }();

        wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
        wgpu::RenderPassEncoder passEncoder = commandEncoder.BeginRenderPass(&renderPass);
        passEncoder.End();
        wgpu::CommandBuffer commands = commandEncoder.Finish();
        queue.Submit(1, &commands);

        const uint32_t renderTargetSize = textureSize >> baseMipLevel;
        switch (type) {
            case Type::Color: {
                std::vector<utils::RGBA8> expected(renderTargetSize * renderTargetSize,
                                                   expectedColor);
                EXPECT_TEXTURE_EQ(expected.data(), renderTarget, {0, 0, baseArrayLayer},
                                  {renderTargetSize, renderTargetSize}, baseMipLevel);
                break;
            }
            case Type::Depth: {
                std::vector<float> expected(renderTargetSize * renderTargetSize, expectedDepth);
                EXPECT_TEXTURE_EQ(expected.data(), renderTarget, {0, 0, baseArrayLayer},
                                  {renderTargetSize, renderTargetSize}, baseMipLevel);
                break;
            }
            case Type::Stencil: {
                std::vector<uint8_t> expected(renderTargetSize * renderTargetSize, expectedStencil);
                EXPECT_TEXTURE_EQ(expected.data(), renderTarget, {0, 0, baseArrayLayer},
                                  {renderTargetSize, renderTargetSize}, baseMipLevel,
                                  wgpu::TextureAspect::StencilOnly);
                break;
            }
        }
    }

    void DoTest(Type type) {
        constexpr uint32_t kArrayLayerCount = 5;
        constexpr uint32_t kMipLevelCount = 4;

        wgpu::TextureFormat format;
        switch (type) {
            case Type::Color:
                format = wgpu::TextureFormat::RGBA8Unorm;
                break;
            case Type::Depth:
                format = wgpu::TextureFormat::Depth32Float;
                break;
            case Type::Stencil:
                format = wgpu::TextureFormat::Depth24PlusStencil8;
                break;
            default:
                UNREACHABLE();
        }

        constexpr uint32_t kTextureSize = kRTSize << (kMipLevelCount - 1);

        wgpu::TextureDescriptor renderTargetDesc;
        renderTargetDesc.dimension = wgpu::TextureDimension::e2D;
        renderTargetDesc.size.width = kTextureSize;
        renderTargetDesc.size.height = kTextureSize;
        renderTargetDesc.size.depthOrArrayLayers = kArrayLayerCount;
        renderTargetDesc.sampleCount = 1;
        renderTargetDesc.format = format;
        renderTargetDesc.mipLevelCount = kMipLevelCount;
        renderTargetDesc.usage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc;

        wgpu::Texture renderTarget = device.CreateTexture(&renderTargetDesc);

        // Test rendering into the first, middle, and last of each of array layer and mip level.
        for (uint32_t arrayLayer : {0u, kArrayLayerCount / 2, kArrayLayerCount - 1u}) {
            for (uint32_t mipLevel : {0u, kMipLevelCount / 2, kMipLevelCount - 1u}) {
                DoSingleTest(type, format, renderTarget, kTextureSize, arrayLayer, mipLevel);
            }
        }
    }
};

// Test rendering into a subresource of a color texture
TEST_P(SubresourceRenderAttachmentTest, ColorTexture) {
    DoTest(Type::Color);
}

// Test rendering into a subresource of a depth texture
TEST_P(SubresourceRenderAttachmentTest, DepthTexture) {
    // TODO(crbug.com/dawn/667): Work around the fact that some platforms do not support reading
    // depth.
    DAWN_TEST_UNSUPPORTED_IF(HasToggleEnabled("disable_depth_read"));

    DoTest(Type::Depth);
}

// Test rendering into a subresource of a stencil texture
TEST_P(SubresourceRenderAttachmentTest, StencilTexture) {
    // TODO(crbug.com/dawn/667): Work around the fact that some platforms are unable to read
    // stencil.
    DAWN_TEST_UNSUPPORTED_IF(HasToggleEnabled("disable_depth_stencil_read"));

    // TODO(crbug.com/dawn/704): Readback after clear via stencil copy does not work
    // on some Intel drivers.
    DAWN_SUPPRESS_TEST_IF(IsMetal() && IsIntel());

    // TODO(crbug.com/dawn/1497): glReadPixels: GL error: HIGH: Invalid format and type combination.
    DAWN_SUPPRESS_TEST_IF(IsANGLE());

    DoTest(Type::Stencil);
}

DAWN_INSTANTIATE_TEST(SubresourceRenderAttachmentTest,
                      D3D12Backend(),
                      D3D12Backend({}, {"use_d3d12_render_pass"}),
                      MetalBackend(),
                      OpenGLBackend(),
                      OpenGLESBackend(),
                      VulkanBackend());
