Resubmit: Use ImmutableString for HLSL texture references
This fixes an issue in the original revision of this patch by adding
a operator<< to TInfoSinkBase that takes ImmutableString as a
parameter.
This also adds ImmutableStringBuilder class, which can be used to
build ImmutableStrings in place without extra allocations if the
maximum length is known in advance.
BUG=angleproject:2267
TEST=angle_unittests
Change-Id: I52e984657a3aba3e6fe67a82b401c6b8de557d18
Reviewed-on: https://chromium-review.googlesource.com/890522
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
diff --git a/src/compiler/translator/ImmutableString.cpp b/src/compiler/translator/ImmutableString.cpp
new file mode 100644
index 0000000..93dad1b
--- /dev/null
+++ b/src/compiler/translator/ImmutableString.cpp
@@ -0,0 +1,15 @@
+//
+// Copyright (c) 2018 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.
+//
+// ImmutableString.cpp: Wrapper for static or pool allocated char arrays, that are guaranteed to be
+// valid and unchanged for the duration of the compilation.
+//
+
+#include "compiler/translator/ImmutableString.h"
+
+std::ostream &operator<<(std::ostream &os, const sh::ImmutableString &str)
+{
+ return os.write(str.data(), str.length());
+}
diff --git a/src/compiler/translator/ImmutableString.h b/src/compiler/translator/ImmutableString.h
index 2957944..a33fec9 100644
--- a/src/compiler/translator/ImmutableString.h
+++ b/src/compiler/translator/ImmutableString.h
@@ -45,10 +45,13 @@
{
}
+ constexpr ImmutableString(const char *data, size_t length) : mData(data), mLength(length) {}
+
ImmutableString(const ImmutableString &) = default;
ImmutableString &operator=(const ImmutableString &) = default;
const char *data() const { return mData ? mData : ""; }
+ size_t length() const { return mLength; }
bool operator<(const ImmutableString &b) const
{
@@ -64,10 +67,12 @@
}
private:
- const char *const mData;
- const size_t mLength;
+ const char *mData;
+ size_t mLength;
};
} // namespace sh
+std::ostream &operator<<(std::ostream &os, const sh::ImmutableString &str);
+
#endif // COMPILER_TRANSLATOR_IMMUTABLESTRING_H_
diff --git a/src/compiler/translator/ImmutableStringBuilder.cpp b/src/compiler/translator/ImmutableStringBuilder.cpp
new file mode 100644
index 0000000..00a8261
--- /dev/null
+++ b/src/compiler/translator/ImmutableStringBuilder.cpp
@@ -0,0 +1,53 @@
+//
+// Copyright (c) 2018 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.
+//
+// ImmutableStringBuilder.cpp: Stringstream-like utility for building pool allocated strings where
+// the maximum length is known in advance.
+//
+
+#include "compiler/translator/ImmutableStringBuilder.h"
+
+namespace sh
+{
+
+ImmutableStringBuilder &ImmutableStringBuilder::operator<<(const ImmutableString &str)
+{
+ ASSERT(mData != nullptr);
+ ASSERT(mPos + str.length() <= mMaxLength);
+ memcpy(mData + mPos, str.data(), str.length());
+ mPos += str.length();
+ return *this;
+}
+
+ImmutableStringBuilder &ImmutableStringBuilder::operator<<(const char *str)
+{
+ ASSERT(mData != nullptr);
+ size_t len = strlen(str);
+ ASSERT(mPos + len <= mMaxLength);
+ memcpy(mData + mPos, str, len);
+ mPos += len;
+ return *this;
+}
+
+ImmutableStringBuilder &ImmutableStringBuilder::operator<<(const char &c)
+{
+ ASSERT(mData != nullptr);
+ ASSERT(mPos + 1 <= mMaxLength);
+ mData[mPos++] = c;
+ return *this;
+}
+
+ImmutableStringBuilder::operator ImmutableString()
+{
+ mData[mPos] = '\0';
+ ImmutableString str(static_cast<const char *>(mData), mPos);
+#if defined(ANGLE_ENABLE_ASSERTS)
+ // Make sure that nothing is added to the string after it is finalized.
+ mData = nullptr;
+#endif
+ return str;
+}
+
+} // namespace sh
diff --git a/src/compiler/translator/ImmutableStringBuilder.h b/src/compiler/translator/ImmutableStringBuilder.h
new file mode 100644
index 0000000..94dcc3b
--- /dev/null
+++ b/src/compiler/translator/ImmutableStringBuilder.h
@@ -0,0 +1,49 @@
+//
+// Copyright (c) 2018 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.
+//
+// ImmutableStringBuilder.h: Stringstream-like utility for building pool allocated strings where the
+// maximum length is known in advance.
+//
+
+#ifndef COMPILER_TRANSLATOR_IMMUTABLESTRINGBUILDER_H_
+#define COMPILER_TRANSLATOR_IMMUTABLESTRINGBUILDER_H_
+
+#include "compiler/translator/ImmutableString.h"
+
+namespace sh
+{
+
+class ImmutableStringBuilder
+{
+ public:
+ ImmutableStringBuilder(size_t maxLength)
+ : mPos(0u), mMaxLength(maxLength), mData(AllocateEmptyPoolCharArray(maxLength))
+ {
+ }
+
+ ImmutableStringBuilder &operator<<(const ImmutableString &str);
+
+ ImmutableStringBuilder &operator<<(const char *str);
+
+ ImmutableStringBuilder &operator<<(const char &c);
+
+ // This invalidates the ImmutableStringBuilder, so it should only be called once.
+ operator ImmutableString();
+
+ private:
+ inline static char *AllocateEmptyPoolCharArray(size_t strLength)
+ {
+ size_t requiredSize = strLength + 1u;
+ return reinterpret_cast<char *>(GetGlobalPoolAllocator()->allocate(requiredSize));
+ }
+
+ size_t mPos;
+ size_t mMaxLength;
+ char *mData;
+};
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_IMMUTABLESTRINGBUILDER_H_
diff --git a/src/compiler/translator/InfoSink.cpp b/src/compiler/translator/InfoSink.cpp
index db26aa6..79e07e3 100644
--- a/src/compiler/translator/InfoSink.cpp
+++ b/src/compiler/translator/InfoSink.cpp
@@ -6,6 +6,8 @@
#include "compiler/translator/InfoSink.h"
+#include "compiler/translator/ImmutableString.h"
+
namespace sh
{
@@ -25,6 +27,12 @@
}
}
+TInfoSinkBase &TInfoSinkBase::operator<<(const ImmutableString &str)
+{
+ sink.append(str.data());
+ return *this;
+}
+
void TInfoSinkBase::location(int file, int line)
{
TPersistStringStream stream;
diff --git a/src/compiler/translator/InfoSink.h b/src/compiler/translator/InfoSink.h
index 2705f48..3f54f4a 100644
--- a/src/compiler/translator/InfoSink.h
+++ b/src/compiler/translator/InfoSink.h
@@ -15,6 +15,8 @@
namespace sh
{
+class ImmutableString;
+
// Returns the fractional part of the given floating-point number.
inline float fractionalPart(float f)
{
@@ -63,6 +65,8 @@
sink.append(str.c_str());
return *this;
}
+ TInfoSinkBase &operator<<(const ImmutableString &str);
+
// Make sure floats are written with correct precision.
TInfoSinkBase &operator<<(float f)
{
diff --git a/src/compiler/translator/TextureFunctionHLSL.cpp b/src/compiler/translator/TextureFunctionHLSL.cpp
index d2b65a6..36898ff 100644
--- a/src/compiler/translator/TextureFunctionHLSL.cpp
+++ b/src/compiler/translator/TextureFunctionHLSL.cpp
@@ -11,6 +11,7 @@
#include "compiler/translator/TextureFunctionHLSL.h"
+#include "compiler/translator/ImmutableStringBuilder.h"
#include "compiler/translator/UtilsHLSL.h"
namespace sh
@@ -104,8 +105,8 @@
void OutputHLSL4SampleFunctionPrefix(TInfoSinkBase &out,
const TextureFunctionHLSL::TextureFunction &textureFunction,
- const TString &textureReference,
- const TString &samplerReference)
+ const ImmutableString &textureReference,
+ const ImmutableString &samplerReference)
{
out << textureReference;
if (IsIntegerSampler(textureFunction.sampler) ||
@@ -450,37 +451,56 @@
void GetTextureReference(TInfoSinkBase &out,
const TextureFunctionHLSL::TextureFunction &textureFunction,
const ShShaderOutput outputType,
- TString *textureReference,
- TString *samplerReference)
+ ImmutableString *textureReference,
+ ImmutableString *samplerReference)
{
if (outputType == SH_HLSL_4_1_OUTPUT)
{
- TString suffix = TextureGroupSuffix(textureFunction.sampler);
+ static const ImmutableString kTexturesStr("textures");
+ static const ImmutableString kSamplersStr("samplers");
+ static const ImmutableString kSamplerIndexStr("[samplerIndex]");
+ static const ImmutableString kTextureIndexStr("[textureIndex]");
+ static const ImmutableString kSamplerArrayIndexStr("[samplerArrayIndex]");
+ ImmutableString suffix(TextureGroupSuffix(textureFunction.sampler));
+
if (TextureGroup(textureFunction.sampler) == HLSL_TEXTURE_2D)
{
- *textureReference = TString("textures") + suffix + "[samplerIndex]";
- *samplerReference = TString("samplers") + suffix + "[samplerIndex]";
+ ImmutableStringBuilder textureRefBuilder(kTexturesStr.length() + suffix.length() +
+ kSamplerIndexStr.length());
+ textureRefBuilder << kTexturesStr << suffix << kSamplerIndexStr;
+ *textureReference = textureRefBuilder;
+ ImmutableStringBuilder samplerRefBuilder(kSamplersStr.length() + suffix.length() +
+ kSamplerIndexStr.length());
+ samplerRefBuilder << kSamplersStr << suffix << kSamplerIndexStr;
+ *samplerReference = samplerRefBuilder;
}
else
{
- out << " const uint textureIndex = samplerIndex - textureIndexOffset" << suffix
- << ";\n";
- *textureReference = TString("textures") + suffix + "[textureIndex]";
- out << " const uint samplerArrayIndex = samplerIndex - samplerIndexOffset" << suffix
- << ";\n";
- *samplerReference = TString("samplers") + suffix + "[samplerArrayIndex]";
+ out << " const uint textureIndex = samplerIndex - textureIndexOffset"
+ << suffix.data() << ";\n";
+ ImmutableStringBuilder textureRefBuilder(kTexturesStr.length() + suffix.length() +
+ kTextureIndexStr.length());
+ textureRefBuilder << kTexturesStr << suffix << kTextureIndexStr;
+ *textureReference = textureRefBuilder;
+
+ out << " const uint samplerArrayIndex = samplerIndex - samplerIndexOffset"
+ << suffix.data() << ";\n";
+ ImmutableStringBuilder samplerRefBuilder(kSamplersStr.length() + suffix.length() +
+ kSamplerArrayIndexStr.length());
+ samplerRefBuilder << kSamplersStr << suffix << kSamplerArrayIndexStr;
+ *samplerReference = samplerRefBuilder;
}
}
else
{
- *textureReference = "x";
- *samplerReference = "s";
+ *textureReference = ImmutableString("x");
+ *samplerReference = ImmutableString("s");
}
}
void OutputTextureSizeFunctionBody(TInfoSinkBase &out,
const TextureFunctionHLSL::TextureFunction &textureFunction,
- const TString &textureReference,
+ const ImmutableString &textureReference,
bool getDimensionsIgnoresBaseLevel)
{
if (IsSampler2DMS(textureFunction.sampler))
@@ -565,7 +585,7 @@
TInfoSinkBase &out,
const TextureFunctionHLSL::TextureFunction &textureFunction,
const ShShaderOutput outputType,
- const TString &textureReference,
+ const ImmutableString &textureReference,
TString *texCoordX,
TString *texCoordY,
TString *texCoordZ)
@@ -811,8 +831,8 @@
TInfoSinkBase &out,
const TextureFunctionHLSL::TextureFunction &textureFunction,
const ShShaderOutput outputType,
- const TString &textureReference,
- const TString &samplerReference,
+ const ImmutableString &textureReference,
+ const ImmutableString &samplerReference,
const TString &texCoordX,
const TString &texCoordY,
const TString &texCoordZ)
@@ -1291,8 +1311,8 @@
// sampling we need to call the function directly on references to the texture and sampler
// arrays. The bug was found using dEQP-GLES3.functional.shaders.discard*loop_texture*
// tests.
- TString textureReference;
- TString samplerReference;
+ ImmutableString textureReference("");
+ ImmutableString samplerReference("");
GetTextureReference(out, textureFunction, outputType, &textureReference, &samplerReference);
if (textureFunction.method == TextureFunction::SIZE)
diff --git a/src/compiler/translator/UtilsHLSL.cpp b/src/compiler/translator/UtilsHLSL.cpp
index 2b8c688..14ba353 100644
--- a/src/compiler/translator/UtilsHLSL.cpp
+++ b/src/compiler/translator/UtilsHLSL.cpp
@@ -218,7 +218,7 @@
return HLSL_TEXTURE_UNKNOWN;
}
-TString TextureString(const HLSLTextureGroup textureGroup)
+const char *TextureString(const HLSLTextureGroup textureGroup)
{
switch (textureGroup)
{
@@ -277,12 +277,12 @@
return "<unknown read texture type>";
}
-TString TextureString(const TBasicType type, TLayoutImageInternalFormat imageInternalFormat)
+const char *TextureString(const TBasicType type, TLayoutImageInternalFormat imageInternalFormat)
{
return TextureString(TextureGroup(type, imageInternalFormat));
}
-TString TextureGroupSuffix(const HLSLTextureGroup type)
+const char *TextureGroupSuffix(const HLSLTextureGroup type)
{
switch (type)
{
@@ -341,7 +341,8 @@
return "<unknown texture type>";
}
-TString TextureGroupSuffix(const TBasicType type, TLayoutImageInternalFormat imageInternalFormat)
+const char *TextureGroupSuffix(const TBasicType type,
+ TLayoutImageInternalFormat imageInternalFormat)
{
return TextureGroupSuffix(TextureGroup(type, imageInternalFormat));
}
diff --git a/src/compiler/translator/UtilsHLSL.h b/src/compiler/translator/UtilsHLSL.h
index fd7715a..a6af60e 100644
--- a/src/compiler/translator/UtilsHLSL.h
+++ b/src/compiler/translator/UtilsHLSL.h
@@ -87,12 +87,12 @@
HLSLTextureGroup TextureGroup(const TBasicType type,
TLayoutImageInternalFormat imageInternalFormat = EiifUnspecified);
-TString TextureString(const HLSLTextureGroup textureGroup);
-TString TextureString(const TBasicType type,
- TLayoutImageInternalFormat imageInternalFormat = EiifUnspecified);
-TString TextureGroupSuffix(const HLSLTextureGroup type);
-TString TextureGroupSuffix(const TBasicType type,
- TLayoutImageInternalFormat imageInternalFormat = EiifUnspecified);
+const char *TextureString(const HLSLTextureGroup textureGroup);
+const char *TextureString(const TBasicType type,
+ TLayoutImageInternalFormat imageInternalFormat = EiifUnspecified);
+const char *TextureGroupSuffix(const HLSLTextureGroup type);
+const char *TextureGroupSuffix(const TBasicType type,
+ TLayoutImageInternalFormat imageInternalFormat = EiifUnspecified);
TString TextureTypeSuffix(const TBasicType type,
TLayoutImageInternalFormat imageInternalFormat = EiifUnspecified);
HLSLRWTextureGroup RWTextureGroup(const TBasicType type,