Hash :
4b1e58d9
Author :
Date :
2024-10-17T09:33:53
Fix for float constant precision in the GLSL backend. Increase the precision of floating point values written out via std::ostringstream. 8 digits is not sufficient to represent all floating point values. Note: the reason the locale test was modified is because it was using a value of 1.9, which has no exact fp32 representation. Increasing the precision causes it to print as 1.8999998 instead of 1.9, failing the test. I've adjusted the value to 1.5, since this does have an exact fp32 representation. (However, note that I couldn't get the test to fail when I removed the locale setting, with either 1.9 or 1.5. Perhaps the locale is being handled at a different level.) Bug: angleproject:374013421 Change-Id: Icb79eb9acd562c83d079f2cc2cdba253220e581e Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/5938473 Commit-Queue: Stephen White <senorblanco@chromium.org> Reviewed-by: Geoff Lang <geofflang@chromium.org>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
//
// 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.
//
// ShCompile_test.cpp
// Test the sh::Compile interface with different parameters.
//
#include <clocale>
#include "GLSLANG/ShaderLang.h"
#include "angle_gl.h"
#include "common/angleutils.h"
#include "common/platform.h"
#include "gtest/gtest.h"
class ShCompileTest : public testing::Test
{
public:
ShCompileTest() {}
protected:
void SetUp() override
{
sh::InitBuiltInResources(&mResources);
mCompiler = sh::ConstructCompiler(GL_FRAGMENT_SHADER, SH_WEBGL_SPEC,
SH_GLSL_COMPATIBILITY_OUTPUT, &mResources);
ASSERT_TRUE(mCompiler != nullptr) << "Compiler could not be constructed.";
}
void TearDown() override
{
if (mCompiler)
{
sh::Destruct(mCompiler);
mCompiler = nullptr;
}
}
void testCompile(const char **shaderStrings, int stringCount, bool expectation)
{
ShCompileOptions options = {};
options.objectCode = true;
options.initOutputVariables = true;
bool success = sh::Compile(mCompiler, shaderStrings, stringCount, options);
const std::string &compileLog = sh::GetInfoLog(mCompiler);
EXPECT_EQ(expectation, success) << compileLog;
}
ShBuiltInResources mResources;
class [[nodiscard]] ScopedRestoreDefaultLocale : angle::NonCopyable
{
public:
ScopedRestoreDefaultLocale();
~ScopedRestoreDefaultLocale();
private:
std::locale defaultLocale;
};
public:
ShHandle mCompiler;
};
ShCompileTest::ScopedRestoreDefaultLocale::ScopedRestoreDefaultLocale()
{
defaultLocale = std::locale();
}
ShCompileTest::ScopedRestoreDefaultLocale::~ScopedRestoreDefaultLocale()
{
std::locale::global(defaultLocale);
}
class ShCompileComputeTest : public ShCompileTest
{
public:
ShCompileComputeTest() {}
protected:
void SetUp() override
{
sh::InitBuiltInResources(&mResources);
mCompiler = sh::ConstructCompiler(GL_COMPUTE_SHADER, SH_WEBGL3_SPEC,
SH_GLSL_COMPATIBILITY_OUTPUT, &mResources);
ASSERT_TRUE(mCompiler != nullptr) << "Compiler could not be constructed.";
}
};
// Test calling sh::Compile with compute shader source string.
TEST_F(ShCompileComputeTest, ComputeShaderString)
{
constexpr char kComputeShaderString[] =
R"(#version 310 es
layout(local_size_x=1) in;
void main()
{
})";
const char *shaderStrings[] = {kComputeShaderString};
testCompile(shaderStrings, 1, true);
}
// Test calling sh::Compile with more than one shader source string.
TEST_F(ShCompileTest, MultipleShaderStrings)
{
const std::string &shaderString1 =
"precision mediump float;\n"
"void main() {\n";
const std::string &shaderString2 =
" gl_FragColor = vec4(0.0);\n"
"}";
const char *shaderStrings[] = {shaderString1.c_str(), shaderString2.c_str()};
testCompile(shaderStrings, 2, true);
}
// Test calling sh::Compile with a tokens split into different shader source strings.
TEST_F(ShCompileTest, TokensSplitInShaderStrings)
{
const std::string &shaderString1 =
"precision mediump float;\n"
"void ma";
const std::string &shaderString2 =
"in() {\n"
"#i";
const std::string &shaderString3 =
"f 1\n"
" gl_FragColor = vec4(0.0);\n"
"#endif\n"
"}";
const char *shaderStrings[] = {shaderString1.c_str(), shaderString2.c_str(),
shaderString3.c_str()};
testCompile(shaderStrings, 3, true);
}
// Parsing floats in shaders can run afoul of locale settings.
// Eg. in de_DE, `strtof("1.5")` will yield `1.0f`. (It's expecting "1.5")
TEST_F(ShCompileTest, DecimalSepLocale)
{
// Locale names are platform dependent, add platform-specific names of locales to be tested here
const std::string availableLocales[] = {
"de_DE",
"de-DE",
"de_DE.UTF-8",
"de_DE.ISO8859-1",
"de_DE.ISO8859-15",
"de_DE@euro",
"de_DE.88591",
"de_DE.88591.en",
"de_DE.iso88591",
"de_DE.ISO-8859-1",
"de_DE.ISO_8859-1",
"de_DE.iso885915",
"de_DE.ISO-8859-15",
"de_DE.ISO_8859-15",
"de_DE.8859-15",
"de_DE.8859-15@euro",
#if !defined(_WIN32)
// TODO(https://crbug.com/972372): Add this test back on Windows once the
// CRT no longer throws on code page sections ('ISO-8859-15@euro') that
// are >= 16 characters long.
"de_DE.ISO-8859-15@euro",
#endif
"de_DE.UTF-8@euro",
"de_DE.utf8",
"German_germany",
"German_Germany",
"German_Germany.1252",
"German_Germany.UTF-8",
"German",
// One ubuntu tester doesn't have a german locale, but da_DK.utf8 has similar float
// representation
"da_DK.utf8"
};
const auto localeExists = [](const std::string name) {
return bool(setlocale(LC_ALL, name.c_str()));
};
const char kSource[] = R"(
void main()
{
gl_FragColor = vec4(1.5);
})";
const char *parts[] = {kSource};
// Ensure the locale is reset after the test runs.
ScopedRestoreDefaultLocale restoreLocale;
for (const std::string &locale : availableLocales)
{
// If the locale doesn't exist on the testing platform, the locale constructor will fail,
// throwing an exception
// We use setlocale() (through localeExists) to test whether a locale
// exists before calling the locale constructor
if (localeExists(locale))
{
std::locale localizedLoc(locale);
ShCompileOptions compileOptions = {};
compileOptions.objectCode = true;
// std::locale::global() must be used instead of setlocale() to affect new streams'
// default locale
std::locale::global(std::locale::classic());
sh::Compile(mCompiler, parts, 1, compileOptions);
std::string referenceOut = sh::GetObjectCode(mCompiler);
EXPECT_NE(referenceOut.find("1.5"), std::string::npos)
<< "float formatted incorrectly with classic locale";
sh::ClearResults(mCompiler);
std::locale::global(localizedLoc);
sh::Compile(mCompiler, parts, 1, compileOptions);
std::string localizedOut = sh::GetObjectCode(mCompiler);
EXPECT_NE(localizedOut.find("1.5"), std::string::npos)
<< "float formatted incorrectly with locale (" << localizedLoc.name() << ") set";
ASSERT_EQ(referenceOut, localizedOut)
<< "different output with locale (" << localizedLoc.name() << ") set";
}
}
}