//
// Copyright 2015 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// D3D11FormatTablesTest:
//   Tests to validate our D3D11 support tables match hardware support.
//

#include "libANGLE/angletypes.h"
#include "libANGLE/Context.h"
#include "libANGLE/formatutils.h"
#include "libANGLE/renderer/d3d/d3d11/Context11.h"
#include "libANGLE/renderer/d3d/d3d11/dxgi_support_table.h"
#include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
#include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
#include "libANGLE/renderer/d3d/d3d11/texture_format_table.h"
#include "test_utils/angle_test_instantiate.h"
#include "test_utils/ANGLETest.h"

using namespace angle;

namespace
{

class D3D11FormatTablesTest : public ANGLETest
{

};

// This test enumerates all GL formats - for each, it queries the D3D support for
// using it as a texture, a render target, and sampling from it in the shader. It
// checks this against our speed-optimized baked tables, and validates they would
// give the same result.
// TODO(jmadill): Find out why in 9_3, some format queries return an error.
// The error seems to appear for formats that are not supported on 9_3.
TEST_P(D3D11FormatTablesTest, TestFormatSupport)
{
    ASSERT_EQ(EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, GetParam().getRenderer());

    // Hack the angle!
    gl::Context *context = reinterpret_cast<gl::Context *>(getEGLWindow()->getContext());
    rx::Context11 *context11 = rx::GetImplAs<rx::Context11>(context);
    rx::Renderer11 *renderer = context11->getRenderer();
    const auto &textureCaps  = renderer->getNativeTextureCaps();

    ID3D11Device *device = renderer->getDevice();

    const gl::FormatSet &allFormats = gl::GetAllSizedInternalFormats();
    for (GLenum internalFormat : allFormats)
    {
        const rx::d3d11::Format &formatInfo =
            rx::d3d11::Format::Get(internalFormat, renderer->getRenderer11DeviceCaps());
        const auto &textureInfo = textureCaps.get(internalFormat);

        // Bits for texturing
        const gl::InternalFormat &internalFormatInfo =
            gl::GetSizedInternalFormatInfo(internalFormat);

        UINT texSupportMask = D3D11_FORMAT_SUPPORT_TEXTURE2D;
        if (internalFormatInfo.depthBits == 0 && internalFormatInfo.stencilBits == 0)
        {
            texSupportMask |= D3D11_FORMAT_SUPPORT_TEXTURECUBE;
            if (GetParam().majorVersion > 2)
            {
                texSupportMask |= D3D11_FORMAT_SUPPORT_TEXTURE3D;
            }
        }

        UINT texSupport  = 0;
        bool texSuccess  = SUCCEEDED(device->CheckFormatSupport(formatInfo.texFormat, &texSupport));
        bool textureable = texSuccess && ((texSupport & texSupportMask) == texSupportMask);
        EXPECT_EQ(textureable, textureInfo.texturable);

        // Bits for mipmap auto-gen.
        bool expectedMipGen = texSuccess && ((texSupport & D3D11_FORMAT_SUPPORT_MIP_AUTOGEN) != 0);
        auto featureLevel   = renderer->getRenderer11DeviceCaps().featureLevel;
        const auto &dxgiSupport = rx::d3d11::GetDXGISupport(formatInfo.texFormat, featureLevel);
        bool actualMipGen =
            ((dxgiSupport.alwaysSupportedFlags & D3D11_FORMAT_SUPPORT_MIP_AUTOGEN) != 0);
        EXPECT_EQ(0u, dxgiSupport.optionallySupportedFlags & D3D11_FORMAT_SUPPORT_MIP_AUTOGEN);
        EXPECT_EQ(expectedMipGen, actualMipGen);

        // Bits for filtering
        UINT filterSupport = 0;
        bool filterSuccess =
            SUCCEEDED(device->CheckFormatSupport(formatInfo.srvFormat, &filterSupport));
        bool filterable = filterSuccess && ((filterSupport & D3D11_FORMAT_SUPPORT_SHADER_SAMPLE) != 0);
        EXPECT_EQ(filterable, textureInfo.filterable);

        // Bits for renderable
        bool renderable = false;
        UINT renderSupport       = 0u;
        DXGI_FORMAT renderFormat = DXGI_FORMAT_UNKNOWN;
        if (internalFormatInfo.depthBits > 0 || internalFormatInfo.stencilBits > 0)
        {
            renderFormat = formatInfo.dsvFormat;
            bool depthSuccess =
                SUCCEEDED(device->CheckFormatSupport(formatInfo.dsvFormat, &renderSupport));
            renderable =
                depthSuccess && ((renderSupport & D3D11_FORMAT_SUPPORT_DEPTH_STENCIL) != 0);
            if (renderable)
            {
                EXPECT_NE(DXGI_FORMAT_UNKNOWN, formatInfo.dsvFormat);
            }
        }
        else
        {
            renderFormat = formatInfo.rtvFormat;
            bool rtSuccess =
                SUCCEEDED(device->CheckFormatSupport(formatInfo.rtvFormat, &renderSupport));
            renderable = rtSuccess && ((renderSupport & D3D11_FORMAT_SUPPORT_RENDER_TARGET) != 0);
            if (renderable)
            {
                EXPECT_NE(DXGI_FORMAT_UNKNOWN, formatInfo.rtvFormat);
            }
        }
        EXPECT_EQ(renderable, textureInfo.renderable);
        if (!textureInfo.sampleCounts.empty())
        {
            EXPECT_TRUE(renderable);
        }

        // Multisample counts
        if (renderable)
        {
            if ((renderSupport & D3D11_FORMAT_SUPPORT_MULTISAMPLE_RENDERTARGET) != 0)
            {
                EXPECT_TRUE(!textureInfo.sampleCounts.empty());
                for (unsigned int sampleCount = 1;
                     sampleCount <= D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; sampleCount *= 2)
                {
                    UINT qualityCount  = 0;
                    bool sampleSuccess = SUCCEEDED(device->CheckMultisampleQualityLevels(
                        renderFormat, sampleCount, &qualityCount));
                    GLuint expectedCount = (!sampleSuccess || qualityCount == 0) ? 0 : 1;
                    EXPECT_EQ(expectedCount, textureInfo.sampleCounts.count(sampleCount));
                }
            }
            else
            {
                EXPECT_TRUE(textureInfo.sampleCounts.empty());
            }
        }
    }
}

ANGLE_INSTANTIATE_TEST(D3D11FormatTablesTest,
                       ES2_D3D11_FL9_3(),
                       ES2_D3D11_FL10_0(),
                       ES2_D3D11_FL10_1(),
                       ES2_D3D11_FL11_0());

} // anonymous namespace
