blob: ae349261c7be7fa3a77e1f0925d832a0a9ee79f5 [file] [log] [blame]
//
// 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 "common/debug.h"
#include "libANGLE/Context.h"
#include "libANGLE/angletypes.h"
#include "libANGLE/formatutils.h"
#include "libANGLE/renderer/d3d/d3d11/Context11.h"
#include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
#include "libANGLE/renderer/d3d/d3d11/dxgi_support_table.h"
#include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
#include "libANGLE/renderer/d3d/d3d11/texture_format_table.h"
#include "test_utils/ANGLETest.h"
#include "test_utils/angle_test_instantiate.h"
#include "util/EGLWindow.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 = static_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) << " for " << gl::FmtHex(internalFormat);
// 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)
<< " for " << gl::FmtHex(internalFormat);
EXPECT_EQ(expectedMipGen, actualMipGen) << " for " << gl::FmtHex(internalFormat);
// 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) << " for " << gl::FmtHex(internalFormat);
// 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)
<< " for " << gl::FmtHex(internalFormat);
}
}
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)
<< " for " << gl::FmtHex(internalFormat);
}
}
EXPECT_EQ(renderable, textureInfo.textureAttachment)
<< " for " << gl::FmtHex(internalFormat);
EXPECT_EQ(renderable, textureInfo.renderbuffer) << " for " << gl::FmtHex(internalFormat);
if (!textureInfo.sampleCounts.empty())
{
EXPECT_TRUE(renderable) << " for " << gl::FmtHex(internalFormat);
}
// 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))
<< " for " << gl::FmtHex(internalFormat);
}
}
else
{
EXPECT_TRUE(textureInfo.sampleCounts.empty())
<< " for " << gl::FmtHex(internalFormat);
}
}
}
}
ANGLE_INSTANTIATE_TEST(D3D11FormatTablesTest,
ES2_D3D11_FL9_3(),
ES2_D3D11_FL10_0(),
ES2_D3D11_FL10_1(),
ES2_D3D11_FL11_0());
} // anonymous namespace