Commit 0728514a by Austin Kinross Committed by Jamie Madill

Fix mipmapped GL_ALPHA UBYTE textures on 9_3

Change-Id: I59020f8152d47091533d69d20fe5ff56e5f96bc1 Reviewed-on: https://chromium-review.googlesource.com/262551Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Tested-by: 's avatarAustin Kinross <aukinros@microsoft.com>
parent 31f8f4f5
...@@ -549,7 +549,28 @@ static inline void InsertLoadFunction(D3D11LoadFunctionMap *map, GLenum internal ...@@ -549,7 +549,28 @@ static inline void InsertLoadFunction(D3D11LoadFunctionMap *map, GLenum internal
(*map)[internalFormat].push_back(TypeLoadFunctionPair(type, loadFunc)); (*map)[internalFormat].push_back(TypeLoadFunctionPair(type, loadFunc));
} }
D3D11LoadFunctionMap BuildD3D11LoadFunctionMap() D3D11LoadFunctionMap BuildD3D11_FL9_3_LoadFunctionMap()
{
D3D11LoadFunctionMap map;
// From GL_EXT_texture_storage. Also used by GL_ALPHA8
// On feature level 9_3, A8_UNORM doesn't support mipmaps, so we must use RGBA8 instead
InsertLoadFunction(&map, GL_ALPHA8_EXT, GL_UNSIGNED_BYTE, LoadA8ToRGBA8);
return map;
}
D3D11LoadFunctionMap BuildD3D11_FL10_0Plus_LoadFunctionMap()
{
D3D11LoadFunctionMap map;
// From GL_EXT_texture_storage. Also used by GL_ALPHA8
InsertLoadFunction(&map, GL_ALPHA8_EXT, GL_UNSIGNED_BYTE, LoadToNative<GLubyte, 1>);
return map;
}
D3D11LoadFunctionMap BuildBaseD3D11LoadFunctionMap()
{ {
D3D11LoadFunctionMap map; D3D11LoadFunctionMap map;
...@@ -654,7 +675,7 @@ D3D11LoadFunctionMap BuildD3D11LoadFunctionMap() ...@@ -654,7 +675,7 @@ D3D11LoadFunctionMap BuildD3D11LoadFunctionMap()
InsertLoadFunction(&map, GL_ALPHA, GL_HALF_FLOAT_OES, LoadA16FToRGBA16F ); InsertLoadFunction(&map, GL_ALPHA, GL_HALF_FLOAT_OES, LoadA16FToRGBA16F );
// From GL_EXT_texture_storage // From GL_EXT_texture_storage
InsertLoadFunction(&map, GL_ALPHA8_EXT, GL_UNSIGNED_BYTE, LoadToNative<GLubyte, 1> ); // GL_ALPHA8_EXT GL_UNSIGNED_BYTE is in the feature-level-specific load function maps, due to differences between 9_3 and 10_0+
InsertLoadFunction(&map, GL_LUMINANCE8_EXT, GL_UNSIGNED_BYTE, LoadL8ToRGBA8 ); InsertLoadFunction(&map, GL_LUMINANCE8_EXT, GL_UNSIGNED_BYTE, LoadL8ToRGBA8 );
InsertLoadFunction(&map, GL_LUMINANCE8_ALPHA8_EXT, GL_UNSIGNED_BYTE, LoadLA8ToRGBA8 ); InsertLoadFunction(&map, GL_LUMINANCE8_ALPHA8_EXT, GL_UNSIGNED_BYTE, LoadLA8ToRGBA8 );
InsertLoadFunction(&map, GL_ALPHA32F_EXT, GL_FLOAT, LoadA32FToRGBA32F ); InsertLoadFunction(&map, GL_ALPHA32F_EXT, GL_FLOAT, LoadA32FToRGBA32F );
...@@ -724,8 +745,8 @@ TextureFormat::TextureFormat() ...@@ -724,8 +745,8 @@ TextureFormat::TextureFormat()
{ {
} }
static inline void InsertD3D11FormatInfo(D3D11ES3FormatMap *map, GLenum internalFormat, DXGI_FORMAT texFormat, static inline void InsertD3D11FormatInfoBase(D3D11ES3FormatMap *formatMap, const D3D11LoadFunctionMap &flLoadFunctions, GLenum internalFormat, DXGI_FORMAT texFormat,
DXGI_FORMAT srvFormat, DXGI_FORMAT rtvFormat, DXGI_FORMAT dsvFormat) DXGI_FORMAT srvFormat, DXGI_FORMAT rtvFormat, DXGI_FORMAT dsvFormat)
{ {
TextureFormat info; TextureFormat info;
info.texFormat = texFormat; info.texFormat = texFormat;
...@@ -809,8 +830,8 @@ static inline void InsertD3D11FormatInfo(D3D11ES3FormatMap *map, GLenum internal ...@@ -809,8 +830,8 @@ static inline void InsertD3D11FormatInfo(D3D11ES3FormatMap *map, GLenum internal
InternalFormatInitializerMap::const_iterator initializerIter = initializerMap.find(internalFormat); InternalFormatInitializerMap::const_iterator initializerIter = initializerMap.find(internalFormat);
info.dataInitializerFunction = (initializerIter != initializerMap.end()) ? initializerIter->second : NULL; info.dataInitializerFunction = (initializerIter != initializerMap.end()) ? initializerIter->second : NULL;
// Gather all the load functions for this internal format // Gather all the load functions for this internal format from the base list
static const D3D11LoadFunctionMap loadFunctions = BuildD3D11LoadFunctionMap(); static const D3D11LoadFunctionMap loadFunctions = BuildBaseD3D11LoadFunctionMap();
D3D11LoadFunctionMap::const_iterator loadFunctionIter = loadFunctions.find(internalFormat); D3D11LoadFunctionMap::const_iterator loadFunctionIter = loadFunctions.find(internalFormat);
if (loadFunctionIter != loadFunctions.end()) if (loadFunctionIter != loadFunctions.end())
{ {
...@@ -823,25 +844,55 @@ static inline void InsertD3D11FormatInfo(D3D11ES3FormatMap *map, GLenum internal ...@@ -823,25 +844,55 @@ static inline void InsertD3D11FormatInfo(D3D11ES3FormatMap *map, GLenum internal
} }
} }
map->insert(std::make_pair(internalFormat, info)); // Gather load functions for this internal format from the feature-level-specific list
D3D11LoadFunctionMap::const_iterator flLoadFunctionIter = flLoadFunctions.find(internalFormat);
if (flLoadFunctionIter != flLoadFunctions.end())
{
const std::vector<TypeLoadFunctionPair> &flLoadFunctionVector = flLoadFunctionIter->second;
for (size_t i = 0; i < flLoadFunctionVector.size(); i++)
{
GLenum type = flLoadFunctionVector[i].first;
LoadImageFunction function = flLoadFunctionVector[i].second;
info.loadFunctions.insert(std::make_pair(type, function));
}
}
formatMap->insert(std::make_pair(internalFormat, info));
}
static inline void InsertD3D11_FL9_3_FormatInfo(D3D11ES3FormatMap *map, GLenum internalFormat, DXGI_FORMAT texFormat,
DXGI_FORMAT srvFormat, DXGI_FORMAT rtvFormat, DXGI_FORMAT dsvFormat)
{
static const D3D11LoadFunctionMap flLoadFunctions = BuildD3D11_FL9_3_LoadFunctionMap();
InsertD3D11FormatInfoBase(map, flLoadFunctions, internalFormat, texFormat, srvFormat, rtvFormat, dsvFormat);
}
static inline void InsertD3D11FormatInfo(D3D11ES3FormatMap *map, GLenum internalFormat, DXGI_FORMAT texFormat,
DXGI_FORMAT srvFormat, DXGI_FORMAT rtvFormat, DXGI_FORMAT dsvFormat)
{
static const D3D11LoadFunctionMap flLoadFunctions = BuildD3D11_FL10_0Plus_LoadFunctionMap();
InsertD3D11FormatInfoBase(map, flLoadFunctions, internalFormat, texFormat, srvFormat, rtvFormat, dsvFormat);
} }
static D3D11ES3FormatMap BuildD3D11_FL9_3FormatOverrideMap() static D3D11ES3FormatMap BuildD3D11_FL9_3FormatOverrideMap()
{ {
// D3D11 Feature Level 9_3 doesn't support as many texture formats as Feature Level 10_0+. // D3D11 Feature Level 9_3 doesn't support as many texture formats as Feature Level 10_0+.
// In particular, it doesn't support: // In particular, it doesn't support:
// - mipmaps on DXGI_FORMAT_A8_NORM
// - *_TYPELESS formats // - *_TYPELESS formats
// - DXGI_FORMAT_D32_FLOAT_S8X24_UINT or DXGI_FORMAT_D32_FLOAT // - DXGI_FORMAT_D32_FLOAT_S8X24_UINT or DXGI_FORMAT_D32_FLOAT
D3D11ES3FormatMap map; D3D11ES3FormatMap map;
// | GL internal format | D3D11 texture format | D3D11 SRV format | D3D11 RTV format | D3D11 DSV format // | GL internal format | D3D11 texture format | D3D11 SRV format | D3D11 RTV format | D3D11 DSV format
InsertD3D11FormatInfo(&map, GL_DEPTH_COMPONENT16, DXGI_FORMAT_D16_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D16_UNORM); InsertD3D11_FL9_3_FormatInfo(&map, GL_ALPHA, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN);
InsertD3D11FormatInfo(&map, GL_DEPTH_COMPONENT24, DXGI_FORMAT_D24_UNORM_S8_UINT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D24_UNORM_S8_UINT); InsertD3D11_FL9_3_FormatInfo(&map, GL_ALPHA8_EXT, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN);
InsertD3D11FormatInfo(&map, GL_DEPTH_COMPONENT32F, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); InsertD3D11_FL9_3_FormatInfo(&map, GL_DEPTH_COMPONENT16, DXGI_FORMAT_D16_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D16_UNORM);
InsertD3D11FormatInfo(&map, GL_DEPTH24_STENCIL8, DXGI_FORMAT_D24_UNORM_S8_UINT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D24_UNORM_S8_UINT); InsertD3D11_FL9_3_FormatInfo(&map, GL_DEPTH_COMPONENT24, DXGI_FORMAT_D24_UNORM_S8_UINT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D24_UNORM_S8_UINT);
InsertD3D11FormatInfo(&map, GL_DEPTH32F_STENCIL8, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); InsertD3D11_FL9_3_FormatInfo(&map, GL_DEPTH_COMPONENT32F, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN);
InsertD3D11FormatInfo(&map, GL_STENCIL_INDEX8, DXGI_FORMAT_D24_UNORM_S8_UINT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D24_UNORM_S8_UINT); InsertD3D11_FL9_3_FormatInfo(&map, GL_DEPTH24_STENCIL8, DXGI_FORMAT_D24_UNORM_S8_UINT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D24_UNORM_S8_UINT);
InsertD3D11_FL9_3_FormatInfo(&map, GL_DEPTH32F_STENCIL8, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN);
InsertD3D11_FL9_3_FormatInfo(&map, GL_STENCIL_INDEX8, DXGI_FORMAT_D24_UNORM_S8_UINT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D24_UNORM_S8_UINT);
return map; return map;
} }
......
#include "ANGLETest.h" #include "ANGLETest.h"
// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against. // Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
ANGLE_TYPED_TEST_CASE(TextureTest, ES2_D3D9, ES2_D3D11); ANGLE_TYPED_TEST_CASE(TextureTest, ES2_D3D9, ES2_D3D11, ES2_D3D11_FL9_3);
template<typename T> template<typename T>
class TextureTest : public ANGLETest class TextureTest : public ANGLETest
...@@ -521,3 +521,86 @@ TYPED_TEST(TextureTest, CopySubImageFloat_RGBA_RGBA) ...@@ -521,3 +521,86 @@ TYPED_TEST(TextureTest, CopySubImageFloat_RGBA_RGBA)
testFloatCopySubImage(4, 4); testFloatCopySubImage(4, 4);
} }
// Port of https://www.khronos.org/registry/webgl/conformance-suites/1.0.3/conformance/textures/texture-npot.html
// Run against GL_ALPHA/UNSIGNED_BYTE format, to ensure that D3D11 Feature Level 9_3 correctly handles GL_ALPHA
TYPED_TEST(TextureTest, TextureNPOT_GL_ALPHA_UBYTE)
{
const int npotTexSize = 5;
const int potTexSize = 4; // Should be less than npotTexSize
GLuint tex2D;
if (extensionEnabled("GL_OES_texture_npot"))
{
// This test isn't applicable if texture_npot is enabled
return;
}
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &tex2D);
glBindTexture(GL_TEXTURE_2D, tex2D);
std::vector<GLubyte> pixels(1 * npotTexSize * npotTexSize);
for (size_t pixelId = 0; pixelId < npotTexSize * npotTexSize; ++pixelId)
{
pixels[pixelId] = 64;
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Check that an NPOT texture not on level 0 generates INVALID_VALUE
glTexImage2D(GL_TEXTURE_2D, 1, GL_ALPHA, npotTexSize, npotTexSize, 0, GL_ALPHA, GL_UNSIGNED_BYTE, pixels.data());
EXPECT_GL_ERROR(GL_INVALID_VALUE);
// Check that an NPOT texture on level 0 succeeds
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, npotTexSize, npotTexSize, 0, GL_ALPHA, GL_UNSIGNED_BYTE, pixels.data());
EXPECT_GL_NO_ERROR();
// Check that generateMipmap fails on NPOT
glGenerateMipmap(GL_TEXTURE_2D);
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
// Check that nothing is drawn if filtering is not correct for NPOT
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glClear(GL_COLOR_BUFFER_BIT);
drawQuad(m2DProgram, "position", 1.0f);
EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 0, 255);
// NPOT texture with TEXTURE_MIN_FILTER not NEAREST or LINEAR should draw with 0,0,0,255
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
glClear(GL_COLOR_BUFFER_BIT);
drawQuad(m2DProgram, "position", 1.0f);
EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 0, 255);
// NPOT texture with TEXTURE_MIN_FILTER set to LINEAR should draw
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glClear(GL_COLOR_BUFFER_BIT);
drawQuad(m2DProgram, "position", 1.0f);
EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 0, 64);
// Check that glTexImage2D for POT texture succeeds
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, potTexSize, potTexSize, 0, GL_ALPHA, GL_UNSIGNED_BYTE, pixels.data());
EXPECT_GL_NO_ERROR();
// Check that generateMipmap for an POT texture succeeds
glGenerateMipmap(GL_TEXTURE_2D);
EXPECT_GL_NO_ERROR();
// POT texture with TEXTURE_MIN_FILTER set to LINEAR_MIPMAP_LINEAR should draw
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glClear(GL_COLOR_BUFFER_BIT);
drawQuad(m2DProgram, "position", 1.0f);
EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 0, 64);
EXPECT_GL_NO_ERROR();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment