Commit 6caa2652 by Mohan Maiya Committed by Commit Bot

Vulkan: Support float textures and renderbuffers

Fixed support in the vulkan backend for legacy GLES2.0 formats (luminance, alpha, luminance_alpha) Correctly exposed the following extensions: OES_texture_float OES_texture_half_float OES_texture_float_linear OES_texture_half_float_linear EXT_color_buffer_float EXT_color_buffer_half_float Some of the above extensions have different requirements depending on other extension support and the context client version, and were incorrectly assuming the most restrictive requirements to be exposed. Implemented end2end tests for: OES_texture_float OES_texture_half_float OES_texture_float_linear OES_texture_half_float_linear EXT_color_buffer_float EXT_color_buffer_half_float Bug: angleproject:2898 Bug: angleproject:2726 Test: ./angle_end2end_tests --gtest_filter='Texture2DFloatTest*' Change-Id: I7024aa1393eadafb5a0fb83c23e9035aae650b67 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1740276 Commit-Queue: Geoff Lang <geofflang@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent c4b1fbd6
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
"src/libANGLE/renderer/gen_load_functions_table.py": "src/libANGLE/renderer/gen_load_functions_table.py":
"e65c50e84fc38ad34d0eb0bebb84aab6", "e65c50e84fc38ad34d0eb0bebb84aab6",
"src/libANGLE/renderer/load_functions_data.json": "src/libANGLE/renderer/load_functions_data.json":
"2225ec8e466cb151fe383fc467d35d65", "16264b125e5410a4791a0c2697a4ff77",
"src/libANGLE/renderer/load_functions_table_autogen.cpp": "src/libANGLE/renderer/load_functions_table_autogen.cpp":
"f4c1c06efea4b69ac29c7f8dff68ea6d" "99e876f3871810c6a7fee8f4ff81b0e6"
} }
\ No newline at end of file
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
"src/libANGLE/renderer/vulkan/gen_vk_format_table.py": "src/libANGLE/renderer/vulkan/gen_vk_format_table.py":
"ed6800108a872709e5e53fde2833aa86", "ed6800108a872709e5e53fde2833aa86",
"src/libANGLE/renderer/vulkan/vk_format_map.json": "src/libANGLE/renderer/vulkan/vk_format_map.json":
"0e63169b162b3720db40e80c80163edb", "d83e8f19044c7709e33412231226a3ae",
"src/libANGLE/renderer/vulkan/vk_format_table_autogen.cpp": "src/libANGLE/renderer/vulkan/vk_format_table_autogen.cpp":
"8b9e38b91ec6b8b23573e2ef9df5284a" "ffc343058ee7f21e0a945558e653c4fc"
} }
\ No newline at end of file
...@@ -257,11 +257,20 @@ static bool DetermineHalfFloatTextureSupport(const TextureCapsMap &textureCaps) ...@@ -257,11 +257,20 @@ static bool DetermineHalfFloatTextureSupport(const TextureCapsMap &textureCaps)
} }
// Checks for GL_OES_texture_half_float_linear support // Checks for GL_OES_texture_half_float_linear support
static bool DetermineHalfFloatTextureFilteringSupport(const TextureCapsMap &textureCaps) static bool DetermineHalfFloatTextureFilteringSupport(const TextureCapsMap &textureCaps,
bool checkLegacyFormats)
{ {
constexpr GLenum requiredFormats[] = { constexpr GLenum requiredFormats[] = {GL_RGBA16F, GL_RGB16F};
GL_RGBA16F, GL_RGB16F, GL_LUMINANCE_ALPHA16F_EXT, GL_LUMINANCE16F_EXT, GL_ALPHA16F_EXT, // If GL_OES_texture_half_float is present, this extension must also support legacy formats
}; // introduced by that extension
constexpr GLenum requiredFormatsES2[] = {GL_LUMINANCE_ALPHA16F_EXT, GL_LUMINANCE16F_EXT,
GL_ALPHA16F_EXT};
if (checkLegacyFormats &&
!GetFormatSupport(textureCaps, requiredFormatsES2, false, true, false, false))
{
return false;
}
return GetFormatSupport(textureCaps, requiredFormats, false, true, false, false); return GetFormatSupport(textureCaps, requiredFormats, false, true, false, false);
} }
...@@ -277,11 +286,26 @@ static bool DetermineFloatTextureSupport(const TextureCapsMap &textureCaps) ...@@ -277,11 +286,26 @@ static bool DetermineFloatTextureSupport(const TextureCapsMap &textureCaps)
} }
// Checks for GL_OES_texture_float_linear support // Checks for GL_OES_texture_float_linear support
static bool DetermineFloatTextureFilteringSupport(const TextureCapsMap &textureCaps) static bool DetermineFloatTextureFilteringSupport(const TextureCapsMap &textureCaps,
bool checkLegacyFormats)
{ {
constexpr GLenum requiredFormats[] = { constexpr GLenum requiredFormats[] = {
GL_RGBA32F, GL_RGB32F, GL_LUMINANCE_ALPHA32F_EXT, GL_LUMINANCE32F_EXT, GL_ALPHA32F_EXT, GL_RGBA32F,
GL_RGB32F,
}; };
// If GL_OES_texture_float is present, this extension must also support legacy formats
// introduced by that extension
constexpr GLenum requiredFormatsES2[] = {
GL_LUMINANCE_ALPHA32F_EXT,
GL_LUMINANCE32F_EXT,
GL_ALPHA32F_EXT,
};
if (checkLegacyFormats &&
!GetFormatSupport(textureCaps, requiredFormatsES2, false, true, false, false))
{
return false;
}
return GetFormatSupport(textureCaps, requiredFormats, false, true, false, false); return GetFormatSupport(textureCaps, requiredFormats, false, true, false, false);
} }
...@@ -664,9 +688,9 @@ void Extensions::setTextureExtensionSupport(const TextureCapsMap &textureCaps) ...@@ -664,9 +688,9 @@ void Extensions::setTextureExtensionSupport(const TextureCapsMap &textureCaps)
textureFormatBGRA8888 = DetermineBGRA8TextureSupport(textureCaps); textureFormatBGRA8888 = DetermineBGRA8TextureSupport(textureCaps);
textureHalfFloat = DetermineHalfFloatTextureSupport(textureCaps); textureHalfFloat = DetermineHalfFloatTextureSupport(textureCaps);
textureHalfFloatLinear = textureHalfFloatLinear =
textureHalfFloat && DetermineHalfFloatTextureFilteringSupport(textureCaps); DetermineHalfFloatTextureFilteringSupport(textureCaps, textureHalfFloat);
textureFloat = DetermineFloatTextureSupport(textureCaps); textureFloat = DetermineFloatTextureSupport(textureCaps);
textureFloatLinear = textureFloat && DetermineFloatTextureFilteringSupport(textureCaps); textureFloatLinear = DetermineFloatTextureFilteringSupport(textureCaps, textureFloat);
textureRG = DetermineRGTextureSupport(textureCaps, textureHalfFloat, textureFloat); textureRG = DetermineRGTextureSupport(textureCaps, textureHalfFloat, textureFloat);
colorBufferHalfFloat = textureHalfFloat && DetermineColorBufferHalfFloatSupport(textureCaps); colorBufferHalfFloat = textureHalfFloat && DetermineColorBufferHalfFloatSupport(textureCaps);
textureCompressionDXT1 = DetermineDXT1TextureSupport(textureCaps); textureCompressionDXT1 = DetermineDXT1TextureSupport(textureCaps);
......
...@@ -3271,6 +3271,15 @@ Extensions Context::generateSupportedExtensions() const ...@@ -3271,6 +3271,15 @@ Extensions Context::generateSupportedExtensions() const
{ {
supportedExtensions.textureSRGBDecode = false; supportedExtensions.textureSRGBDecode = false;
} }
// Don't expose GL_OES_texture_float_linear without full legacy float texture support
// The renderer may report OES_texture_float_linear without OES_texture_float
// This is valid in a GLES 3.0 context, but not in a GLES 2.0 context
if (!(supportedExtensions.textureFloat && supportedExtensions.textureHalfFloat))
{
supportedExtensions.textureFloatLinear = false;
supportedExtensions.textureHalfFloatLinear = false;
}
} }
if (getClientVersion() < ES_3_1) if (getClientVersion() < ES_3_1)
...@@ -3287,6 +3296,20 @@ Extensions Context::generateSupportedExtensions() const ...@@ -3287,6 +3296,20 @@ Extensions Context::generateSupportedExtensions() const
{ {
// FIXME(geofflang): Don't support EXT_sRGB in non-ES2 contexts // FIXME(geofflang): Don't support EXT_sRGB in non-ES2 contexts
// supportedExtensions.sRGB = false; // supportedExtensions.sRGB = false;
// If colorBufferFloat is disabled but colorBufferHalfFloat is enabled, then we will expose
// some floating-point formats as color buffer targets but reject blits between fixed-point
// and floating-point formats (this behavior is only enabled in colorBufferFloat, and must
// be rejected if only colorBufferHalfFloat is enabled).
// dEQP does not check for this, and will assume that floating-point and fixed-point formats
// can be blit onto each other if the format is available.
// We require colorBufferFloat to be present in order to enable colorBufferHalfFloat, so
// that blitting is always allowed if the requested formats are exposed and have the correct
// feature capabilities
if (!supportedExtensions.colorBufferFloat)
{
supportedExtensions.colorBufferHalfFloat = false;
}
} }
// Some extensions are always available because they are implemented in the GL layer. // Some extensions are always available because they are implemented in the GL layer.
......
...@@ -144,6 +144,15 @@ static bool RequireExtOrExtOrExt(const Version &, const Extensions &extensions) ...@@ -144,6 +144,15 @@ static bool RequireExtOrExtOrExt(const Version &, const Extensions &extensions)
return extensions.*bool1 || extensions.*bool2 || extensions.*bool3; return extensions.*bool1 || extensions.*bool2 || extensions.*bool3;
} }
static bool UnsizedHalfFloatOESRGBATextureAttachmentSupport(const Version &clientVersion,
const Extensions &extensions)
{
// dEQP requires ES3 + EXT_color_buffer_half_float for rendering to RGB[A] + HALF_FLOAT_OES
// textures but WebGL allows it with just ES 2.0
return (clientVersion.major >= 3 || extensions.webglCompatibility) &&
extensions.colorBufferHalfFloat;
}
// R8, RG8 // R8, RG8
static bool SizedRGSupport(const Version &clientVersion, const Extensions &extensions) static bool SizedRGSupport(const Version &clientVersion, const Extensions &extensions)
{ {
...@@ -1004,8 +1013,8 @@ static InternalFormatInfoMap BuildInternalFormatInfoMap() ...@@ -1004,8 +1013,8 @@ static InternalFormatInfoMap BuildInternalFormatInfoMap()
AddRGBAFormat(&map, GL_RGBA, false, 16, 16, 16, 16, 0, GL_RGBA, GL_HALF_FLOAT, GL_FLOAT, false, NeverSupported, NeverSupported, NeverSupported, NeverSupported); AddRGBAFormat(&map, GL_RGBA, false, 16, 16, 16, 16, 0, GL_RGBA, GL_HALF_FLOAT, GL_FLOAT, false, NeverSupported, NeverSupported, NeverSupported, NeverSupported);
AddRGBAFormat(&map, GL_RED, false, 16, 0, 0, 0, 0, GL_RED, GL_HALF_FLOAT_OES, GL_FLOAT, false, RequireExtAndExt<&Extensions::textureHalfFloat, &Extensions::textureRG>, RequireExt<&Extensions::textureHalfFloatLinear>, AlwaysSupported, NeverSupported); AddRGBAFormat(&map, GL_RED, false, 16, 0, 0, 0, 0, GL_RED, GL_HALF_FLOAT_OES, GL_FLOAT, false, RequireExtAndExt<&Extensions::textureHalfFloat, &Extensions::textureRG>, RequireExt<&Extensions::textureHalfFloatLinear>, AlwaysSupported, NeverSupported);
AddRGBAFormat(&map, GL_RG, false, 16, 16, 0, 0, 0, GL_RG, GL_HALF_FLOAT_OES, GL_FLOAT, false, RequireExtAndExt<&Extensions::textureHalfFloat, &Extensions::textureRG>, RequireExt<&Extensions::textureHalfFloatLinear>, AlwaysSupported, NeverSupported); AddRGBAFormat(&map, GL_RG, false, 16, 16, 0, 0, 0, GL_RG, GL_HALF_FLOAT_OES, GL_FLOAT, false, RequireExtAndExt<&Extensions::textureHalfFloat, &Extensions::textureRG>, RequireExt<&Extensions::textureHalfFloatLinear>, AlwaysSupported, NeverSupported);
AddRGBAFormat(&map, GL_RGB, false, 16, 16, 16, 0, 0, GL_RGB, GL_HALF_FLOAT_OES, GL_FLOAT, false, RequireExt<&Extensions::textureHalfFloat>, RequireExt<&Extensions::textureHalfFloatLinear>, RequireExt<&Extensions::colorBufferHalfFloat>, NeverSupported); AddRGBAFormat(&map, GL_RGB, false, 16, 16, 16, 0, 0, GL_RGB, GL_HALF_FLOAT_OES, GL_FLOAT, false, RequireExt<&Extensions::textureHalfFloat>, RequireExt<&Extensions::textureHalfFloatLinear>, UnsizedHalfFloatOESRGBATextureAttachmentSupport, NeverSupported);
AddRGBAFormat(&map, GL_RGBA, false, 16, 16, 16, 16, 0, GL_RGBA, GL_HALF_FLOAT_OES, GL_FLOAT, false, RequireExt<&Extensions::textureHalfFloat>, RequireExt<&Extensions::textureHalfFloatLinear>, RequireExt<&Extensions::colorBufferHalfFloat>, NeverSupported); AddRGBAFormat(&map, GL_RGBA, false, 16, 16, 16, 16, 0, GL_RGBA, GL_HALF_FLOAT_OES, GL_FLOAT, false, RequireExt<&Extensions::textureHalfFloat>, RequireExt<&Extensions::textureHalfFloatLinear>, UnsizedHalfFloatOESRGBATextureAttachmentSupport, NeverSupported);
AddRGBAFormat(&map, GL_RED, false, 32, 0, 0, 0, 0, GL_RED, GL_FLOAT, GL_FLOAT, false, RequireExtAndExt<&Extensions::textureFloat, &Extensions::textureRG>, RequireExt<&Extensions::textureFloatLinear>, AlwaysSupported, NeverSupported); AddRGBAFormat(&map, GL_RED, false, 32, 0, 0, 0, 0, GL_RED, GL_FLOAT, GL_FLOAT, false, RequireExtAndExt<&Extensions::textureFloat, &Extensions::textureRG>, RequireExt<&Extensions::textureFloatLinear>, AlwaysSupported, NeverSupported);
AddRGBAFormat(&map, GL_RG, false, 32, 32, 0, 0, 0, GL_RG, GL_FLOAT, GL_FLOAT, false, RequireExtAndExt<&Extensions::textureFloat, &Extensions::textureRG>, RequireExt<&Extensions::textureFloatLinear>, AlwaysSupported, NeverSupported); AddRGBAFormat(&map, GL_RG, false, 32, 32, 0, 0, 0, GL_RG, GL_FLOAT, GL_FLOAT, false, RequireExtAndExt<&Extensions::textureFloat, &Extensions::textureRG>, RequireExt<&Extensions::textureFloatLinear>, AlwaysSupported, NeverSupported);
AddRGBAFormat(&map, GL_RGB, false, 32, 32, 32, 0, 0, GL_RGB, GL_FLOAT, GL_FLOAT, false, RequireExt<&Extensions::textureFloat>, RequireExt<&Extensions::textureFloatLinear>, NeverSupported, NeverSupported); AddRGBAFormat(&map, GL_RGB, false, 32, 32, 32, 0, 0, GL_RGB, GL_FLOAT, GL_FLOAT, false, RequireExt<&Extensions::textureFloat>, RequireExt<&Extensions::textureFloatLinear>, NeverSupported, NeverSupported);
......
...@@ -54,6 +54,9 @@ ...@@ -54,6 +54,9 @@
} }
}, },
"GL_ALPHA32F_EXT": { "GL_ALPHA32F_EXT": {
"R32_FLOAT": {
"GL_FLOAT": "LoadToNative<GLfloat, 1>"
},
"NONE": { "NONE": {
"GL_FLOAT": "LoadA32FToRGBA32F" "GL_FLOAT": "LoadA32FToRGBA32F"
} }
...@@ -93,6 +96,9 @@ ...@@ -93,6 +96,9 @@
} }
}, },
"GL_LUMINANCE32F_EXT": { "GL_LUMINANCE32F_EXT": {
"R32_FLOAT": {
"GL_FLOAT": "LoadToNative<GLfloat, 1>"
},
"NONE": { "NONE": {
"GL_FLOAT": "LoadL32FToRGBA32F" "GL_FLOAT": "LoadL32FToRGBA32F"
} }
...@@ -529,6 +535,10 @@ ...@@ -529,6 +535,10 @@
} }
}, },
"GL_LUMINANCE_ALPHA16F_EXT": { "GL_LUMINANCE_ALPHA16F_EXT": {
"R16G16_FLOAT": {
"GL_HALF_FLOAT": "LoadToNative<GLhalf, 2>",
"GL_HALF_FLOAT_OES": "LoadToNative<GLhalf, 2>"
},
"NONE": { "NONE": {
"GL_HALF_FLOAT": "LoadLA16FToRGBA16F", "GL_HALF_FLOAT": "LoadLA16FToRGBA16F",
"GL_HALF_FLOAT_OES": "LoadLA16FToRGBA16F" "GL_HALF_FLOAT_OES": "LoadLA16FToRGBA16F"
...@@ -613,6 +623,9 @@ ...@@ -613,6 +623,9 @@
} }
}, },
"GL_LUMINANCE_ALPHA32F_EXT": { "GL_LUMINANCE_ALPHA32F_EXT": {
"R32G32_FLOAT": {
"GL_FLOAT": "LoadToNative<GLfloat, 2>"
},
"NONE": { "NONE": {
"GL_FLOAT": "LoadLA32FToRGBA32F" "GL_FLOAT": "LoadLA32FToRGBA32F"
} }
...@@ -670,6 +683,10 @@ ...@@ -670,6 +683,10 @@
} }
}, },
"GL_LUMINANCE16F_EXT": { "GL_LUMINANCE16F_EXT": {
"R16_FLOAT": {
"GL_HALF_FLOAT": "LoadToNative<GLhalf, 1>",
"GL_HALF_FLOAT_OES": "LoadToNative<GLhalf, 1>"
},
"NONE": { "NONE": {
"GL_HALF_FLOAT": "LoadL16FToRGBA16F", "GL_HALF_FLOAT": "LoadL16FToRGBA16F",
"GL_HALF_FLOAT_OES": "LoadL16FToRGBA16F" "GL_HALF_FLOAT_OES": "LoadL16FToRGBA16F"
...@@ -696,6 +713,10 @@ ...@@ -696,6 +713,10 @@
} }
}, },
"GL_ALPHA16F_EXT": { "GL_ALPHA16F_EXT": {
"R16_FLOAT": {
"GL_HALF_FLOAT": "LoadToNative<GLhalf, 1>",
"GL_HALF_FLOAT_OES": "LoadToNative<GLhalf, 1>"
},
"NONE": { "NONE": {
"GL_HALF_FLOAT": "LoadA16FToRGBA16F", "GL_HALF_FLOAT": "LoadA16FToRGBA16F",
"GL_HALF_FLOAT_OES": "LoadA16FToRGBA16F" "GL_HALF_FLOAT_OES": "LoadA16FToRGBA16F"
......
...@@ -112,6 +112,20 @@ LoadImageFunctionInfo ALPHA_to_default(GLenum type) ...@@ -112,6 +112,20 @@ LoadImageFunctionInfo ALPHA_to_default(GLenum type)
} }
} }
LoadImageFunctionInfo ALPHA16F_EXT_to_R16_FLOAT(GLenum type)
{
switch (type)
{
case GL_HALF_FLOAT:
return LoadImageFunctionInfo(LoadToNative<GLhalf, 1>, false);
case GL_HALF_FLOAT_OES:
return LoadImageFunctionInfo(LoadToNative<GLhalf, 1>, false);
default:
UNREACHABLE();
return LoadImageFunctionInfo(UnreachableLoadFunction, true);
}
}
LoadImageFunctionInfo ALPHA16F_EXT_to_default(GLenum type) LoadImageFunctionInfo ALPHA16F_EXT_to_default(GLenum type)
{ {
switch (type) switch (type)
...@@ -126,6 +140,18 @@ LoadImageFunctionInfo ALPHA16F_EXT_to_default(GLenum type) ...@@ -126,6 +140,18 @@ LoadImageFunctionInfo ALPHA16F_EXT_to_default(GLenum type)
} }
} }
LoadImageFunctionInfo ALPHA32F_EXT_to_R32_FLOAT(GLenum type)
{
switch (type)
{
case GL_FLOAT:
return LoadImageFunctionInfo(LoadToNative<GLfloat, 1>, false);
default:
UNREACHABLE();
return LoadImageFunctionInfo(UnreachableLoadFunction, true);
}
}
LoadImageFunctionInfo ALPHA32F_EXT_to_default(GLenum type) LoadImageFunctionInfo ALPHA32F_EXT_to_default(GLenum type)
{ {
switch (type) switch (type)
...@@ -1538,6 +1564,20 @@ LoadImageFunctionInfo LUMINANCE_to_default(GLenum type) ...@@ -1538,6 +1564,20 @@ LoadImageFunctionInfo LUMINANCE_to_default(GLenum type)
} }
} }
LoadImageFunctionInfo LUMINANCE16F_EXT_to_R16_FLOAT(GLenum type)
{
switch (type)
{
case GL_HALF_FLOAT:
return LoadImageFunctionInfo(LoadToNative<GLhalf, 1>, false);
case GL_HALF_FLOAT_OES:
return LoadImageFunctionInfo(LoadToNative<GLhalf, 1>, false);
default:
UNREACHABLE();
return LoadImageFunctionInfo(UnreachableLoadFunction, true);
}
}
LoadImageFunctionInfo LUMINANCE16F_EXT_to_default(GLenum type) LoadImageFunctionInfo LUMINANCE16F_EXT_to_default(GLenum type)
{ {
switch (type) switch (type)
...@@ -1552,6 +1592,18 @@ LoadImageFunctionInfo LUMINANCE16F_EXT_to_default(GLenum type) ...@@ -1552,6 +1592,18 @@ LoadImageFunctionInfo LUMINANCE16F_EXT_to_default(GLenum type)
} }
} }
LoadImageFunctionInfo LUMINANCE32F_EXT_to_R32_FLOAT(GLenum type)
{
switch (type)
{
case GL_FLOAT:
return LoadImageFunctionInfo(LoadToNative<GLfloat, 1>, false);
default:
UNREACHABLE();
return LoadImageFunctionInfo(UnreachableLoadFunction, true);
}
}
LoadImageFunctionInfo LUMINANCE32F_EXT_to_default(GLenum type) LoadImageFunctionInfo LUMINANCE32F_EXT_to_default(GLenum type)
{ {
switch (type) switch (type)
...@@ -1654,6 +1706,20 @@ LoadImageFunctionInfo LUMINANCE_ALPHA_to_default(GLenum type) ...@@ -1654,6 +1706,20 @@ LoadImageFunctionInfo LUMINANCE_ALPHA_to_default(GLenum type)
} }
} }
LoadImageFunctionInfo LUMINANCE_ALPHA16F_EXT_to_R16G16_FLOAT(GLenum type)
{
switch (type)
{
case GL_HALF_FLOAT:
return LoadImageFunctionInfo(LoadToNative<GLhalf, 2>, false);
case GL_HALF_FLOAT_OES:
return LoadImageFunctionInfo(LoadToNative<GLhalf, 2>, false);
default:
UNREACHABLE();
return LoadImageFunctionInfo(UnreachableLoadFunction, true);
}
}
LoadImageFunctionInfo LUMINANCE_ALPHA16F_EXT_to_default(GLenum type) LoadImageFunctionInfo LUMINANCE_ALPHA16F_EXT_to_default(GLenum type)
{ {
switch (type) switch (type)
...@@ -1668,6 +1734,18 @@ LoadImageFunctionInfo LUMINANCE_ALPHA16F_EXT_to_default(GLenum type) ...@@ -1668,6 +1734,18 @@ LoadImageFunctionInfo LUMINANCE_ALPHA16F_EXT_to_default(GLenum type)
} }
} }
LoadImageFunctionInfo LUMINANCE_ALPHA32F_EXT_to_R32G32_FLOAT(GLenum type)
{
switch (type)
{
case GL_FLOAT:
return LoadImageFunctionInfo(LoadToNative<GLfloat, 2>, false);
default:
UNREACHABLE();
return LoadImageFunctionInfo(UnreachableLoadFunction, true);
}
}
LoadImageFunctionInfo LUMINANCE_ALPHA32F_EXT_to_default(GLenum type) LoadImageFunctionInfo LUMINANCE_ALPHA32F_EXT_to_default(GLenum type)
{ {
switch (type) switch (type)
...@@ -2939,9 +3017,25 @@ LoadFunctionMap GetLoadFunctionsMap(GLenum internalFormat, FormatID angleFormat) ...@@ -2939,9 +3017,25 @@ LoadFunctionMap GetLoadFunctionsMap(GLenum internalFormat, FormatID angleFormat)
} }
} }
case GL_ALPHA16F_EXT: case GL_ALPHA16F_EXT:
return ALPHA16F_EXT_to_default; {
switch (angleFormat)
{
case FormatID::R16_FLOAT:
return ALPHA16F_EXT_to_R16_FLOAT;
default:
return ALPHA16F_EXT_to_default;
}
}
case GL_ALPHA32F_EXT: case GL_ALPHA32F_EXT:
return ALPHA32F_EXT_to_default; {
switch (angleFormat)
{
case FormatID::R32_FLOAT:
return ALPHA32F_EXT_to_R32_FLOAT;
default:
return ALPHA32F_EXT_to_default;
}
}
case GL_ALPHA8_EXT: case GL_ALPHA8_EXT:
{ {
switch (angleFormat) switch (angleFormat)
...@@ -3404,9 +3498,25 @@ LoadFunctionMap GetLoadFunctionsMap(GLenum internalFormat, FormatID angleFormat) ...@@ -3404,9 +3498,25 @@ LoadFunctionMap GetLoadFunctionsMap(GLenum internalFormat, FormatID angleFormat)
} }
} }
case GL_LUMINANCE16F_EXT: case GL_LUMINANCE16F_EXT:
return LUMINANCE16F_EXT_to_default; {
switch (angleFormat)
{
case FormatID::R16_FLOAT:
return LUMINANCE16F_EXT_to_R16_FLOAT;
default:
return LUMINANCE16F_EXT_to_default;
}
}
case GL_LUMINANCE32F_EXT: case GL_LUMINANCE32F_EXT:
return LUMINANCE32F_EXT_to_default; {
switch (angleFormat)
{
case FormatID::R32_FLOAT:
return LUMINANCE32F_EXT_to_R32_FLOAT;
default:
return LUMINANCE32F_EXT_to_default;
}
}
case GL_LUMINANCE8_ALPHA8_EXT: case GL_LUMINANCE8_ALPHA8_EXT:
{ {
switch (angleFormat) switch (angleFormat)
...@@ -3446,9 +3556,25 @@ LoadFunctionMap GetLoadFunctionsMap(GLenum internalFormat, FormatID angleFormat) ...@@ -3446,9 +3556,25 @@ LoadFunctionMap GetLoadFunctionsMap(GLenum internalFormat, FormatID angleFormat)
} }
} }
case GL_LUMINANCE_ALPHA16F_EXT: case GL_LUMINANCE_ALPHA16F_EXT:
return LUMINANCE_ALPHA16F_EXT_to_default; {
switch (angleFormat)
{
case FormatID::R16G16_FLOAT:
return LUMINANCE_ALPHA16F_EXT_to_R16G16_FLOAT;
default:
return LUMINANCE_ALPHA16F_EXT_to_default;
}
}
case GL_LUMINANCE_ALPHA32F_EXT: case GL_LUMINANCE_ALPHA32F_EXT:
return LUMINANCE_ALPHA32F_EXT_to_default; {
switch (angleFormat)
{
case FormatID::R32G32_FLOAT:
return LUMINANCE_ALPHA32F_EXT_to_R32G32_FLOAT;
default:
return LUMINANCE_ALPHA32F_EXT_to_default;
}
}
case GL_R11F_G11F_B10F: case GL_R11F_G11F_B10F:
{ {
switch (angleFormat) switch (angleFormat)
......
...@@ -462,7 +462,14 @@ GLenum FramebufferVk::getImplementationColorReadFormat(const gl::Context *contex ...@@ -462,7 +462,14 @@ GLenum FramebufferVk::getImplementationColorReadFormat(const gl::Context *contex
GLenum FramebufferVk::getImplementationColorReadType(const gl::Context *context) const GLenum FramebufferVk::getImplementationColorReadType(const gl::Context *context) const
{ {
return GetReadAttachmentInfo(context, mRenderTargetCache.getColorRead(mState)).type; GLenum readType = GetReadAttachmentInfo(context, mRenderTargetCache.getColorRead(mState)).type;
if (context->getClientMajorVersion() < 3 && readType == GL_HALF_FLOAT)
{
// GL_HALF_FLOAT was not introduced until GLES 3.0, and has a different value from
// GL_HALF_FLOAT_OES
readType = GL_HALF_FLOAT_OES;
}
return readType;
} }
angle::Result FramebufferVk::readPixels(const gl::Context *context, angle::Result FramebufferVk::readPixels(const gl::Context *context,
......
...@@ -172,6 +172,18 @@ ...@@ -172,6 +172,18 @@
"A32_FLOAT": { "A32_FLOAT": {
"image": "R32_FLOAT" "image": "R32_FLOAT"
}, },
"L16_FLOAT": {
"image": "R16_FLOAT"
},
"L32_FLOAT": {
"image": "R32_FLOAT"
},
"L16A16_FLOAT": {
"image": "R16G16_FLOAT"
},
"L32A32_FLOAT": {
"image": "R32G32_FLOAT"
},
"A8_UNORM": { "A8_UNORM": {
"image": "R8_UNORM" "image": "R8_UNORM"
}, },
......
...@@ -978,19 +978,35 @@ void Format::initialize(RendererVk *renderer, const angle::Format &angleFormat) ...@@ -978,19 +978,35 @@ void Format::initialize(RendererVk *renderer, const angle::Format &angleFormat)
break; break;
case angle::FormatID::L16A16_FLOAT: case angle::FormatID::L16A16_FLOAT:
// This format is not implemented in Vulkan. internalFormat = GL_LUMINANCE_ALPHA16F_EXT;
imageFormatID = angle::FormatID::R16G16_FLOAT;
vkImageFormat = VK_FORMAT_R16G16_SFLOAT;
imageInitializerFunction = nullptr;
break; break;
case angle::FormatID::L16_FLOAT: case angle::FormatID::L16_FLOAT:
// This format is not implemented in Vulkan. internalFormat = GL_LUMINANCE16F_EXT;
imageFormatID = angle::FormatID::R16_FLOAT;
vkImageFormat = VK_FORMAT_R16_SFLOAT;
imageInitializerFunction = nullptr;
break; break;
case angle::FormatID::L32A32_FLOAT: case angle::FormatID::L32A32_FLOAT:
// This format is not implemented in Vulkan. internalFormat = GL_LUMINANCE_ALPHA32F_EXT;
imageFormatID = angle::FormatID::R32G32_FLOAT;
vkImageFormat = VK_FORMAT_R32G32_SFLOAT;
imageInitializerFunction = nullptr;
break; break;
case angle::FormatID::L32_FLOAT: case angle::FormatID::L32_FLOAT:
// This format is not implemented in Vulkan. internalFormat = GL_LUMINANCE32F_EXT;
imageFormatID = angle::FormatID::R32_FLOAT;
vkImageFormat = VK_FORMAT_R32_SFLOAT;
imageInitializerFunction = nullptr;
break; break;
case angle::FormatID::L8A8_UNORM: case angle::FormatID::L8A8_UNORM:
......
...@@ -342,55 +342,51 @@ void MapSwizzleState(const ContextVk *contextVk, ...@@ -342,55 +342,51 @@ void MapSwizzleState(const ContextVk *contextVk,
gl::SwizzleState internalSwizzle; gl::SwizzleState internalSwizzle;
switch (format.internalFormat) if (angleFormat.isLUMA())
{ {
case GL_LUMINANCE8_OES: GLenum swizzleRGB, swizzleA;
internalSwizzle.swizzleRed = GL_RED; if (angleFormat.luminanceBits > 0)
internalSwizzle.swizzleGreen = GL_RED; {
internalSwizzle.swizzleBlue = GL_RED; swizzleRGB = GL_RED;
swizzleA = (angleFormat.alphaBits > 0 ? GL_GREEN : GL_ONE);
}
else
{
swizzleRGB = GL_ZERO;
swizzleA = GL_RED;
}
internalSwizzle.swizzleRed = swizzleRGB;
internalSwizzle.swizzleGreen = swizzleRGB;
internalSwizzle.swizzleBlue = swizzleRGB;
internalSwizzle.swizzleAlpha = swizzleA;
}
else
{
if (angleFormat.hasDepthOrStencilBits())
{
bool hasRed = angleFormat.depthBits > 0;
// In OES_depth_texture/ARB_depth_texture, depth
// textures are treated as luminance.
// If the internalformat was not sized, use OES_depth_texture behavior
bool hasGB = hasRed && !sized;
internalSwizzle.swizzleRed = hasRed ? GL_RED : GL_ZERO;
internalSwizzle.swizzleGreen = hasGB ? GL_RED : GL_ZERO;
internalSwizzle.swizzleBlue = hasGB ? GL_RED : GL_ZERO;
internalSwizzle.swizzleAlpha = GL_ONE; internalSwizzle.swizzleAlpha = GL_ONE;
break; }
case GL_LUMINANCE8_ALPHA8_OES: else
internalSwizzle.swizzleRed = GL_RED; {
internalSwizzle.swizzleGreen = GL_RED; // Color bits are all zero for blocked formats
internalSwizzle.swizzleBlue = GL_RED; if (!angleFormat.isBlock)
internalSwizzle.swizzleAlpha = GL_GREEN;
break;
case GL_ALPHA8_OES:
internalSwizzle.swizzleRed = GL_ZERO;
internalSwizzle.swizzleGreen = GL_ZERO;
internalSwizzle.swizzleBlue = GL_ZERO;
internalSwizzle.swizzleAlpha = GL_RED;
break;
default:
if (angleFormat.hasDepthOrStencilBits())
{
bool hasRed = angleFormat.depthBits > 0;
// In OES_depth_texture/ARB_depth_texture, depth
// textures are treated as luminance.
// If the internalformat was not sized, use OES_depth_texture behavior
bool hasGB = hasRed && !sized;
internalSwizzle.swizzleRed = hasRed ? GL_RED : GL_ZERO;
internalSwizzle.swizzleGreen = hasGB ? GL_RED : GL_ZERO;
internalSwizzle.swizzleBlue = hasGB ? GL_RED : GL_ZERO;
internalSwizzle.swizzleAlpha = GL_ONE;
}
else
{ {
if (angleFormat.isBlock)
{
// Color bits are all zero for blocked formats, so the
// below will erroneously set swizzle to (0, 0, 0, 1).
break;
}
// Set any missing channel to default in case the emulated format has that channel. // Set any missing channel to default in case the emulated format has that channel.
internalSwizzle.swizzleRed = angleFormat.redBits > 0 ? GL_RED : GL_ZERO; internalSwizzle.swizzleRed = angleFormat.redBits > 0 ? GL_RED : GL_ZERO;
internalSwizzle.swizzleGreen = angleFormat.greenBits > 0 ? GL_GREEN : GL_ZERO; internalSwizzle.swizzleGreen = angleFormat.greenBits > 0 ? GL_GREEN : GL_ZERO;
internalSwizzle.swizzleBlue = angleFormat.blueBits > 0 ? GL_BLUE : GL_ZERO; internalSwizzle.swizzleBlue = angleFormat.blueBits > 0 ? GL_BLUE : GL_ZERO;
internalSwizzle.swizzleAlpha = angleFormat.alphaBits > 0 ? GL_ALPHA : GL_ONE; internalSwizzle.swizzleAlpha = angleFormat.alphaBits > 0 ? GL_ALPHA : GL_ONE;
} }
break; }
} }
ComposeSwizzleState(internalSwizzle, swizzleState, swizzleStateOut); ComposeSwizzleState(internalSwizzle, swizzleState, swizzleStateOut);
} }
......
...@@ -2021,8 +2021,13 @@ angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk, GLuint ...@@ -2021,8 +2021,13 @@ angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk, GLuint
mipWidth = nextMipWidth; mipWidth = nextMipWidth;
mipHeight = nextMipHeight; mipHeight = nextMipHeight;
commandBuffer->blitImage(mImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, mImage, bool formatSupportsLinearFiltering = contextVk->getRenderer()->hasImageFormatFeatureBits(
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, VK_FILTER_LINEAR); getFormat().vkImageFormat, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT);
commandBuffer->blitImage(
mImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, mImage,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit,
formatSupportsLinearFiltering ? VK_FILTER_LINEAR : VK_FILTER_NEAREST);
} }
// Transition the last mip level to the same layout as all the other ones, so we can declare // Transition the last mip level to the same layout as all the other ones, so we can declare
......
...@@ -13,11 +13,14 @@ using namespace angle; ...@@ -13,11 +13,14 @@ using namespace angle;
namespace namespace
{ {
constexpr unsigned int kPixelTolerance = 1u; constexpr GLuint kPixelTolerance = 1u;
constexpr GLfloat kPixelTolerance32F = 0.01f;
// Take a pixel, and reset the components not covered by the format to default // Take a pixel, and reset the components not covered by the format to default
// values. In particular, the default value for the alpha component is 255 // values. In particular, the default value for the alpha component is 255
// (1.0 as unsigned normalized fixed point value). // (1.0 as unsigned normalized fixed point value).
// For legacy formats, the components may be reordered to match the color that
// would be created if a pixel of that format was initialized from the given color
GLColor SliceFormatColor(GLenum format, GLColor full) GLColor SliceFormatColor(GLenum format, GLColor full)
{ {
switch (format) switch (format)
...@@ -30,12 +33,43 @@ GLColor SliceFormatColor(GLenum format, GLColor full) ...@@ -30,12 +33,43 @@ GLColor SliceFormatColor(GLenum format, GLColor full)
return GLColor(full.R, full.G, full.B, 255u); return GLColor(full.R, full.G, full.B, 255u);
case GL_RGBA: case GL_RGBA:
return full; return full;
case GL_LUMINANCE:
return GLColor(full.R, full.R, full.R, 255u);
case GL_ALPHA:
return GLColor(0, 0, 0, full.R);
case GL_LUMINANCE_ALPHA:
return GLColor(full.R, full.R, full.R, full.G);
default: default:
EXPECT_TRUE(false); EXPECT_TRUE(false);
return GLColor::white; return GLColor::white;
} }
} }
// As above, for 32F colors
GLColor32F SliceFormatColor32F(GLenum format, GLColor32F full)
{
switch (format)
{
case GL_RED:
return GLColor32F(full.R, 0.0f, 0.0f, 1.0f);
case GL_RG:
return GLColor32F(full.R, full.G, 0.0f, 1.0f);
case GL_RGB:
return GLColor32F(full.R, full.G, full.B, 1.0f);
case GL_RGBA:
return full;
case GL_LUMINANCE:
return GLColor32F(full.R, full.R, full.R, 1.0f);
case GL_ALPHA:
return GLColor32F(0.0f, 0.0f, 0.0f, full.R);
case GL_LUMINANCE_ALPHA:
return GLColor32F(full.R, full.R, full.R, full.G);
default:
EXPECT_TRUE(false);
return GLColor32F(1.0f, 1.0f, 1.0f, 1.0f);
}
}
class TexCoordDrawTest : public ANGLETest class TexCoordDrawTest : public ANGLETest
{ {
protected: protected:
...@@ -1754,7 +1788,7 @@ TEST_P(Texture2DTest, TexStorageWithPBO) ...@@ -1754,7 +1788,7 @@ TEST_P(Texture2DTest, TexStorageWithPBO)
} }
} }
// See description on testFloatCopySubImage // Tests CopySubImage for float formats
TEST_P(Texture2DTest, CopySubImageFloat_R_R) TEST_P(Texture2DTest, CopySubImageFloat_R_R)
{ {
testFloatCopySubImage(1, 1); testFloatCopySubImage(1, 1);
...@@ -1783,7 +1817,7 @@ TEST_P(Texture2DTest, CopySubImageFloat_RGB_RG) ...@@ -1783,7 +1817,7 @@ TEST_P(Texture2DTest, CopySubImageFloat_RGB_RG)
TEST_P(Texture2DTest, CopySubImageFloat_RGB_RGB) TEST_P(Texture2DTest, CopySubImageFloat_RGB_RGB)
{ {
// TODO(cwallez): Fix on Linux Intel drivers (http://anglebug.com/1346) // TODO(cwallez): Fix on Linux Intel drivers (http://anglebug.com/1346)
ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux()); ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
// Ignore SDK layers messages on D3D11 FL 9.3 (http://anglebug.com/1284) // Ignore SDK layers messages on D3D11 FL 9.3 (http://anglebug.com/1284)
ANGLE_SKIP_TEST_IF(IsD3D11_FL93()); ANGLE_SKIP_TEST_IF(IsD3D11_FL93());
...@@ -1811,10 +1845,6 @@ TEST_P(Texture2DTest, CopySubImageFloat_RGBA_RGB) ...@@ -1811,10 +1845,6 @@ TEST_P(Texture2DTest, CopySubImageFloat_RGBA_RGB)
TEST_P(Texture2DTest, CopySubImageFloat_RGBA_RGBA) TEST_P(Texture2DTest, CopySubImageFloat_RGBA_RGBA)
{ {
// TODO(lucferron): This test fails only on linux and intel.
// http://anglebug.com/2726
ANGLE_SKIP_TEST_IF(IsVulkan() && IsLinux() && IsIntel());
// Ignore SDK layers messages on D3D11 FL 9.3 (http://anglebug.com/1284) // Ignore SDK layers messages on D3D11 FL 9.3 (http://anglebug.com/1284)
ANGLE_SKIP_TEST_IF(IsD3D11_FL93()); ANGLE_SKIP_TEST_IF(IsD3D11_FL93());
...@@ -4028,11 +4058,11 @@ class Texture2DRGTest : public Texture2DTest ...@@ -4028,11 +4058,11 @@ class Texture2DRGTest : public Texture2DTest
glGenRenderbuffers(1, &mRenderbuffer); glGenRenderbuffers(1, &mRenderbuffer);
glBindTexture(GL_TEXTURE_2D, mRenderableTexture); glBindTexture(GL_TEXTURE_2D, mRenderableTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glBindTexture(GL_TEXTURE_2D, mTestTexture); glBindTexture(GL_TEXTURE_2D, mTestTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
...@@ -4139,7 +4169,7 @@ TEST_P(Texture2DRGTest, TextureRGFloatTest) ...@@ -4139,7 +4169,7 @@ TEST_P(Texture2DRGTest, TextureRGFloatTest)
} }
// Test half-float texture formats enabled by the GL_EXT_texture_rg extension. // Test half-float texture formats enabled by the GL_EXT_texture_rg extension.
TEST_P(Texture2DRGTest, TextureRGFHalfFloatTest) TEST_P(Texture2DRGTest, TextureRGHalfFloatTest)
{ {
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_rg")); ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_rg"));
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_texture_half_float")); ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_texture_half_float"));
...@@ -4158,6 +4188,450 @@ TEST_P(Texture2DRGTest, TextureRGFHalfFloatTest) ...@@ -4158,6 +4188,450 @@ TEST_P(Texture2DRGTest, TextureRGFHalfFloatTest)
testRGTexture(SliceFormatColor(GL_RG_EXT, expectedColor)); testRGTexture(SliceFormatColor(GL_RG_EXT, expectedColor));
} }
class Texture2DFloatTest : public Texture2DTest
{
protected:
Texture2DFloatTest()
: Texture2DTest(), mRenderableTexture(0), mTestTexture(0), mFBO(0), mRenderbuffer(0)
{}
void testSetUp() override
{
Texture2DTest::testSetUp();
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &mRenderableTexture);
glGenTextures(1, &mTestTexture);
glGenFramebuffers(1, &mFBO);
glGenRenderbuffers(1, &mRenderbuffer);
setUpProgram();
glUseProgram(mProgram);
glUniform1i(mTexture2DUniformLocation, 0);
glBindTexture(GL_TEXTURE_2D, mRenderableTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
mRenderableTexture, 0);
ASSERT_GL_NO_ERROR();
}
void testTearDown() override
{
glDeleteTextures(1, &mRenderableTexture);
glDeleteTextures(1, &mTestTexture);
glDeleteFramebuffers(1, &mFBO);
glDeleteRenderbuffers(1, &mRenderbuffer);
Texture2DTest::testTearDown();
}
void testFloatTextureSample(GLenum internalFormat, GLenum format, GLenum type)
{
constexpr GLfloat imageDataFloat[] = {
0.2f,
0.3f,
0.4f,
0.5f,
};
constexpr GLhalf imageDataHalf[] = {
0x3266,
0x34CD,
0x3666,
0x3800,
};
GLColor expectedValue;
for (int i = 0; i < 4; i++)
{
expectedValue[i] = static_cast<GLubyte>(imageDataFloat[i] * 255.0f);
}
const GLvoid *imageData;
switch (type)
{
case GL_FLOAT:
imageData = imageDataFloat;
break;
case GL_HALF_FLOAT:
case GL_HALF_FLOAT_OES:
imageData = imageDataHalf;
break;
default:
imageData = nullptr;
}
ASSERT(imageData != nullptr);
glBindTexture(GL_TEXTURE_2D, mTestTexture);
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, 1, 1, 0, format, type, imageData);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
drawQuad(mProgram, "position", 0.5f);
EXPECT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_NEAR(0, 0, SliceFormatColor(format, expectedValue), kPixelTolerance);
}
void testFloatTextureLinear(GLenum internalFormat, GLenum format, GLenum type)
{
int numComponents;
switch (format)
{
case GL_RGBA:
numComponents = 4;
break;
case GL_RGB:
numComponents = 3;
break;
case GL_LUMINANCE_ALPHA:
numComponents = 2;
break;
case GL_LUMINANCE:
case GL_ALPHA:
numComponents = 1;
break;
default:
numComponents = 0;
}
ASSERT(numComponents > 0);
constexpr GLfloat pixelIntensitiesFloat[] = {0.0f, 1.0f, 0.0f, 1.0f};
constexpr GLhalf pixelIntensitiesHalf[] = {0x0000, 0x3C00, 0x0000, 0x3C00};
GLfloat imageDataFloat[16];
GLhalf imageDataHalf[16];
for (int i = 0; i < 4; i++)
{
for (int c = 0; c < numComponents; c++)
{
imageDataFloat[i * numComponents + c] = pixelIntensitiesFloat[i];
imageDataHalf[i * numComponents + c] = pixelIntensitiesHalf[i];
}
}
const GLvoid *imageData;
switch (type)
{
case GL_FLOAT:
imageData = imageDataFloat;
break;
case GL_HALF_FLOAT:
case GL_HALF_FLOAT_OES:
imageData = imageDataHalf;
break;
default:
imageData = nullptr;
}
ASSERT(imageData != nullptr);
glBindTexture(GL_TEXTURE_2D, mTestTexture);
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, 2, 2, 0, format, type, imageData);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
drawQuad(mProgram, "position", 0.5f);
EXPECT_GL_NO_ERROR();
// Source texture contains 2 black pixels and 2 white pixels, we sample in the center so we
// should expect the final value to be gray (halfway in-between)
EXPECT_PIXEL_COLOR_NEAR(0, 0, SliceFormatColor(format, GLColor(127u, 127u, 127u, 127u)),
kPixelTolerance);
}
bool performFloatTextureRender(GLenum internalFormat,
GLenum renderBufferFormat,
GLenum format,
GLenum type)
{
glBindTexture(GL_TEXTURE_2D, mTestTexture);
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, 1, 1, 0, format, type, nullptr);
glBindTexture(GL_TEXTURE_2D, 0);
glBindRenderbuffer(GL_RENDERBUFFER, mRenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, renderBufferFormat, 1, 1);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
mRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
EXPECT_GL_NO_ERROR();
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
{
return false;
}
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_GL_NO_ERROR();
return true;
}
GLuint mRenderableTexture;
GLuint mTestTexture;
GLuint mFBO;
GLuint mRenderbuffer;
};
class Texture2DFloatTestES3 : public Texture2DFloatTest
{
protected:
void testFloatTextureRender(GLenum internalFormat, GLenum format, GLenum type)
{
bool framebufferComplete =
performFloatTextureRender(internalFormat, internalFormat, format, type);
EXPECT_TRUE(framebufferComplete);
EXPECT_PIXEL_COLOR32F_NEAR(0, 0,
SliceFormatColor32F(format, GLColor32F(1.0f, 1.0f, 1.0f, 1.0f)),
kPixelTolerance32F);
}
};
class Texture2DFloatTestES2 : public Texture2DFloatTest
{
protected:
bool checkFloatTextureRender(GLenum renderBufferFormat, GLenum format, GLenum type)
{
bool framebufferComplete =
performFloatTextureRender(format, renderBufferFormat, format, type);
if (!framebufferComplete)
{
return false;
}
EXPECT_PIXEL_COLOR32F_NEAR(0, 0,
SliceFormatColor32F(format, GLColor32F(1.0f, 1.0f, 1.0f, 1.0f)),
kPixelTolerance32F);
return true;
}
};
// Test texture sampling for ES3 float texture formats
TEST_P(Texture2DFloatTestES3, TextureFloatSampleBasicTest)
{
testFloatTextureSample(GL_RGBA32F, GL_RGBA, GL_FLOAT);
testFloatTextureSample(GL_RGB32F, GL_RGB, GL_FLOAT);
}
// Test texture sampling for ES2 float texture formats
TEST_P(Texture2DFloatTestES2, TextureFloatSampleBasicTest)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_texture_float"));
testFloatTextureSample(GL_RGBA, GL_RGBA, GL_FLOAT);
testFloatTextureSample(GL_RGB, GL_RGB, GL_FLOAT);
}
// Test texture sampling for ES3 half float texture formats
TEST_P(Texture2DFloatTestES3, TextureHalfFloatSampleBasicTest)
{
testFloatTextureSample(GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT);
testFloatTextureSample(GL_RGB16F, GL_RGB, GL_HALF_FLOAT);
}
// Test texture sampling for ES2 half float texture formats
TEST_P(Texture2DFloatTestES2, TextureHalfFloatSampleBasicTest)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_texture_half_float"));
testFloatTextureSample(GL_RGBA, GL_RGBA, GL_HALF_FLOAT_OES);
testFloatTextureSample(GL_RGB, GL_RGB, GL_HALF_FLOAT_OES);
}
// Test texture sampling for legacy GLES 2.0 float texture formats in ES3
TEST_P(Texture2DFloatTestES3, TextureFloatSampleLegacyTest)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_texture_float"));
testFloatTextureSample(GL_LUMINANCE, GL_LUMINANCE, GL_FLOAT);
testFloatTextureSample(GL_ALPHA, GL_ALPHA, GL_FLOAT);
testFloatTextureSample(GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_FLOAT);
if (IsGLExtensionEnabled("GL_EXT_texture_storage"))
{
testFloatTextureSample(GL_LUMINANCE32F_EXT, GL_LUMINANCE, GL_FLOAT);
testFloatTextureSample(GL_ALPHA32F_EXT, GL_ALPHA, GL_FLOAT);
testFloatTextureSample(GL_LUMINANCE_ALPHA32F_EXT, GL_LUMINANCE_ALPHA, GL_FLOAT);
}
}
// Test texture sampling for legacy GLES 2.0 float texture formats in ES2
TEST_P(Texture2DFloatTestES2, TextureFloatSampleLegacyTest)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_texture_float"));
testFloatTextureSample(GL_LUMINANCE, GL_LUMINANCE, GL_FLOAT);
testFloatTextureSample(GL_ALPHA, GL_ALPHA, GL_FLOAT);
testFloatTextureSample(GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_FLOAT);
}
// Test texture sampling for legacy GLES 2.0 half float texture formats in ES3
TEST_P(Texture2DFloatTestES3, TextureHalfFloatSampleLegacyTest)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_texture_half_float"));
testFloatTextureSample(GL_LUMINANCE, GL_LUMINANCE, GL_HALF_FLOAT_OES);
testFloatTextureSample(GL_ALPHA, GL_ALPHA, GL_HALF_FLOAT_OES);
testFloatTextureSample(GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES);
if (IsGLExtensionEnabled("GL_EXT_texture_storage"))
{
testFloatTextureSample(GL_LUMINANCE16F_EXT, GL_LUMINANCE, GL_HALF_FLOAT);
testFloatTextureSample(GL_ALPHA16F_EXT, GL_ALPHA, GL_HALF_FLOAT);
testFloatTextureSample(GL_LUMINANCE_ALPHA16F_EXT, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT);
}
}
// Test texture sampling for legacy GLES 2.0 half float texture formats in ES2
TEST_P(Texture2DFloatTestES2, TextureHalfFloatSampleLegacyTest)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_texture_half_float"));
testFloatTextureSample(GL_LUMINANCE, GL_LUMINANCE, GL_HALF_FLOAT_OES);
testFloatTextureSample(GL_ALPHA, GL_ALPHA, GL_HALF_FLOAT_OES);
testFloatTextureSample(GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES);
}
// Test linear sampling for ES3 32F formats
TEST_P(Texture2DFloatTestES3, TextureFloatLinearTest)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_texture_float_linear"));
testFloatTextureLinear(GL_RGBA32F, GL_RGBA, GL_FLOAT);
testFloatTextureLinear(GL_RGB32F, GL_RGB, GL_FLOAT);
}
// Test linear sampling for ES2 32F formats
TEST_P(Texture2DFloatTestES2, TextureFloatLinearTest)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_texture_float_linear"));
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_texture_float"));
testFloatTextureLinear(GL_RGBA, GL_RGBA, GL_FLOAT);
}
// Test linear sampling for ES3 16F formats
TEST_P(Texture2DFloatTestES3, TextureHalfFloatLinearTest)
{
// Half float formats must be linearly filterable in GLES 3.0 core
testFloatTextureLinear(GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT);
testFloatTextureLinear(GL_RGB16F, GL_RGB, GL_HALF_FLOAT);
}
// Test linear sampling for ES2 16F formats
TEST_P(Texture2DFloatTestES2, TextureHalfFloatLinearTest)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_texture_half_float_linear"));
testFloatTextureLinear(GL_RGBA, GL_RGBA, GL_HALF_FLOAT_OES);
testFloatTextureLinear(GL_RGB, GL_RGB, GL_HALF_FLOAT_OES);
}
// Test linear sampling for legacy GLES 2.0 32F formats in ES3
TEST_P(Texture2DFloatTestES3, TextureFloatLinearLegacyTest)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_texture_float"));
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_texture_float_linear"));
testFloatTextureLinear(GL_LUMINANCE, GL_LUMINANCE, GL_FLOAT);
testFloatTextureLinear(GL_ALPHA, GL_ALPHA, GL_FLOAT);
testFloatTextureLinear(GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_FLOAT);
if (IsGLExtensionEnabled("GL_EXT_texture_storage"))
{
testFloatTextureLinear(GL_LUMINANCE32F_EXT, GL_LUMINANCE, GL_FLOAT);
testFloatTextureLinear(GL_ALPHA32F_EXT, GL_ALPHA, GL_FLOAT);
testFloatTextureLinear(GL_LUMINANCE_ALPHA32F_EXT, GL_LUMINANCE_ALPHA, GL_FLOAT);
}
}
// Test linear sampling for legacy GLES 2.0 32F formats in ES2
TEST_P(Texture2DFloatTestES2, TextureFloatLinearLegacyTest)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_texture_float"));
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_texture_float_linear"));
testFloatTextureLinear(GL_LUMINANCE, GL_LUMINANCE, GL_FLOAT);
testFloatTextureLinear(GL_ALPHA, GL_ALPHA, GL_FLOAT);
testFloatTextureLinear(GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_FLOAT);
}
// Test linear sampling for legacy GLES 2.0 16F formats in ES3
TEST_P(Texture2DFloatTestES3, TextureHalfFloatLinearLegacyTest)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_texture_half_float"));
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_texture_half_float_linear"));
testFloatTextureLinear(GL_LUMINANCE, GL_LUMINANCE, GL_HALF_FLOAT_OES);
testFloatTextureLinear(GL_ALPHA, GL_ALPHA, GL_HALF_FLOAT_OES);
testFloatTextureLinear(GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES);
if (IsGLExtensionEnabled("GL_EXT_texture_storage"))
{
testFloatTextureLinear(GL_LUMINANCE16F_EXT, GL_LUMINANCE, GL_HALF_FLOAT);
testFloatTextureLinear(GL_ALPHA16F_EXT, GL_ALPHA, GL_HALF_FLOAT);
testFloatTextureLinear(GL_LUMINANCE_ALPHA16F_EXT, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT);
}
}
// Test linear sampling for legacy GLES 2.0 16F formats in ES2
TEST_P(Texture2DFloatTestES2, TextureHalfFloatLinearLegacyTest)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_texture_half_float"));
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_texture_half_float_linear"));
testFloatTextureLinear(GL_LUMINANCE, GL_LUMINANCE, GL_HALF_FLOAT_OES);
testFloatTextureLinear(GL_ALPHA, GL_ALPHA, GL_HALF_FLOAT_OES);
testFloatTextureLinear(GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES);
}
// Test color-renderability for ES3 float and half float textures
TEST_P(Texture2DFloatTestES3, TextureFloatRenderTest)
{
// EXT_color_buffer_float covers float, half float, and 11-11-10 float formats
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_color_buffer_float"));
testFloatTextureRender(GL_R32F, GL_RED, GL_FLOAT);
testFloatTextureRender(GL_RG32F, GL_RG, GL_FLOAT);
testFloatTextureRender(GL_RGBA32F, GL_RGBA, GL_FLOAT);
testFloatTextureRender(GL_R16F, GL_RED, GL_HALF_FLOAT);
testFloatTextureRender(GL_RG16F, GL_RG, GL_HALF_FLOAT);
testFloatTextureRender(GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT);
testFloatTextureRender(GL_R11F_G11F_B10F, GL_RGB, GL_FLOAT);
}
// Test color-renderability for ES2 half float textures
TEST_P(Texture2DFloatTestES2, TextureFloatRenderTest)
{
// EXT_color_buffer_half_float requires at least one format to be renderable, but does not
// require a specific one
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_color_buffer_half_float"));
bool atLeastOneSupported = false;
if (IsGLExtensionEnabled("GL_OES_texture_half_float") ||
IsGLExtensionEnabled("GL_OES_texture_half_float"))
{
atLeastOneSupported |= checkFloatTextureRender(GL_R16F_EXT, GL_RED_EXT, GL_HALF_FLOAT_OES);
atLeastOneSupported |= checkFloatTextureRender(GL_RG16F_EXT, GL_RG_EXT, GL_HALF_FLOAT_OES);
}
if (IsGLExtensionEnabled("GL_OES_texture_half_float"))
{
atLeastOneSupported |= checkFloatTextureRender(GL_RGB16F_EXT, GL_RGB, GL_HALF_FLOAT_OES);
// If OES_texture_half_float is supported, then RGBA half float textures must be renderable
bool rgbaSupported = checkFloatTextureRender(GL_RGBA16F_EXT, GL_RGBA, GL_HALF_FLOAT_OES);
EXPECT_TRUE(rgbaSupported);
atLeastOneSupported |= rgbaSupported;
}
EXPECT_TRUE(atLeastOneSupported);
}
// Test that UNPACK_SKIP_IMAGES doesn't have an effect on 2D texture uploads. // Test that UNPACK_SKIP_IMAGES doesn't have an effect on 2D texture uploads.
// GLES 3.0.4 section 3.8.3. // GLES 3.0.4 section 3.8.3.
TEST_P(Texture2DTestES3, UnpackSkipImages2D) TEST_P(Texture2DTestES3, UnpackSkipImages2D)
...@@ -5261,6 +5735,16 @@ ANGLE_INSTANTIATE_TEST(Texture2DRGTest, ...@@ -5261,6 +5735,16 @@ ANGLE_INSTANTIATE_TEST(Texture2DRGTest,
ES3_OPENGLES(), ES3_OPENGLES(),
ES2_VULKAN(), ES2_VULKAN(),
ES3_VULKAN()); ES3_VULKAN());
ANGLE_INSTANTIATE_TEST(Texture2DFloatTestES3,
ES3_D3D11(),
ES3_OPENGL(),
ES3_OPENGLES(),
ES3_VULKAN());
ANGLE_INSTANTIATE_TEST(Texture2DFloatTestES2,
ES2_D3D11(),
ES2_OPENGL(),
ES2_OPENGLES(),
ES2_VULKAN());
ANGLE_INSTANTIATE_TEST(TextureCubeTestES3, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES()); ANGLE_INSTANTIATE_TEST(TextureCubeTestES3, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
ANGLE_INSTANTIATE_TEST(Texture2DIntegerTestES3, ES3_D3D11(), ES3_OPENGL()); ANGLE_INSTANTIATE_TEST(Texture2DIntegerTestES3, ES3_D3D11(), ES3_OPENGL());
ANGLE_INSTANTIATE_TEST(TextureCubeIntegerTestES3, ES3_D3D11(), ES3_OPENGL()); ANGLE_INSTANTIATE_TEST(TextureCubeIntegerTestES3, ES3_D3D11(), ES3_OPENGL());
......
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