Commit b079c7af by Olli Etuaho Committed by Commit Bot

Wrap integer textures with correct wrap mode in HLSL

The wrap mode information for all three dimensions is packed to a single integer in order to conserve sampler metadata space. Only one int4 vector is used for the metadata for a single sampler. The sampler metadata is now packed into a struct instead of an array of integers in order to make the code more readable and maintainable. The internalFormatBits field is not removed in this patch. It's better to remove it in a separate patch, so restoring it is easier in case it will be used for optimizing some of the texture sampling functions. The wrap mode passed in sampler metadata is used to wrap the texture coordinates in the code generated to implement ESSL 3.00 integer texture sampling built-ins. Those dEQP-GLES3.functional.texture.units.* tests that sample from integer cube maps still fail on Intel D3D after this change, presumably due to driver issues. BUG=angleproject:1244 BUG=angleproject:1095 BUG=angleproject:1092 TEST=dEQP-GLES3.functional.texture.units.* (all pass on NVIDIA), dEQP-GLES3.functional.shaders.texture_functions.* (no regressions) Change-Id: I4e31e5796086f9cc290c6f1f8c4380a768758d71 Reviewed-on: https://chromium-review.googlesource.com/336638Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
parent f4863a45
...@@ -74,6 +74,42 @@ const TConstantUnion *WriteConstantUnionArray(TInfoSinkBase &out, ...@@ -74,6 +74,42 @@ const TConstantUnion *WriteConstantUnionArray(TInfoSinkBase &out,
return constUnionIterated; return constUnionIterated;
} }
void OutputIntTexCoordWrap(TInfoSinkBase &out,
const char *wrapMode,
const char *size,
const TString &texCoord,
const TString &texCoordOffset,
const char *texCoordOutName)
{
// GLES 3.0.4 table 3.22 specifies how the wrap modes work. We don't use the formulas verbatim
// but rather use equivalent formulas that map better to HLSL.
out << "int " << texCoordOutName << ";\n";
out << "float " << texCoordOutName << "Offset = " << texCoord << " + float(" << texCoordOffset
<< ") / " << size << ";\n";
// CLAMP_TO_EDGE
out << "if (" << wrapMode << " == 1)\n";
out << "{\n";
out << " " << texCoordOutName << " = clamp(int(floor(" << size << " * " << texCoordOutName
<< "Offset)), 0, int(" << size << ") - 1);\n";
out << "}\n";
// MIRRORED_REPEAT
out << "else if (" << wrapMode << " == 3)\n";
out << "{\n";
out << " float coordWrapped = 1.0 - abs(frac(abs(" << texCoordOutName
<< "Offset) * 0.5) * 2.0 - 1.0);\n";
out << " " << texCoordOutName << " = int(floor(" << size << " * coordWrapped));\n";
out << "}\n";
// REPEAT
out << "else\n";
out << "{\n";
out << " " << texCoordOutName << " = int(floor(" << size << " * frac(" << texCoordOutName
<< "Offset)));\n";
out << "}\n";
}
} // namespace } // namespace
namespace sh namespace sh
...@@ -864,7 +900,7 @@ void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *built ...@@ -864,7 +900,7 @@ void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *built
if (textureFunction->method == TextureFunction::SIZE) if (textureFunction->method == TextureFunction::SIZE)
{ {
out << "int baseLevel = samplerMetadata[samplerIndex].x;\n"; out << "int baseLevel = samplerMetadata[samplerIndex].baseLevel;\n";
if (IsSampler2D(textureFunction->sampler) || IsSamplerCube(textureFunction->sampler)) if (IsSampler2D(textureFunction->sampler) || IsSamplerCube(textureFunction->sampler))
{ {
if (IsSamplerArray(textureFunction->sampler) || if (IsSamplerArray(textureFunction->sampler) ||
...@@ -1169,8 +1205,26 @@ void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *built ...@@ -1169,8 +1205,26 @@ void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *built
else UNREACHABLE(); else UNREACHABLE();
// Convert from normalized floating-point to integer // Convert from normalized floating-point to integer
texCoordX = "int(floor(width * frac(" + texCoordX + ")))"; out << "int wrapS = samplerMetadata[samplerIndex].wrapModes & 0x3;\n";
texCoordY = "int(floor(height * frac(" + texCoordY + ")))"; if (textureFunction->offset)
{
OutputIntTexCoordWrap(out, "wrapS", "width", texCoordX, "offset.x", "tix");
}
else
{
OutputIntTexCoordWrap(out, "wrapS", "width", texCoordX, "0", "tix");
}
texCoordX = "tix";
out << "int wrapT = (samplerMetadata[samplerIndex].wrapModes >> 2) & 0x3;\n";
if (textureFunction->offset)
{
OutputIntTexCoordWrap(out, "wrapT", "height", texCoordY, "offset.y", "tiy");
}
else
{
OutputIntTexCoordWrap(out, "wrapT", "height", texCoordY, "0", "tiy");
}
texCoordY = "tiy";
if (IsSamplerArray(textureFunction->sampler)) if (IsSamplerArray(textureFunction->sampler))
{ {
...@@ -1179,7 +1233,16 @@ void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *built ...@@ -1179,7 +1233,16 @@ void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *built
else if (!IsSamplerCube(textureFunction->sampler) && else if (!IsSamplerCube(textureFunction->sampler) &&
!IsSampler2D(textureFunction->sampler)) !IsSampler2D(textureFunction->sampler))
{ {
texCoordZ = "int(floor(depth * frac(" + texCoordZ + ")))"; out << "int wrapR = (samplerMetadata[samplerIndex].wrapModes >> 4) & 0x3;\n";
if (textureFunction->offset)
{
OutputIntTexCoordWrap(out, "wrapR", "depth", texCoordZ, "offset.z", "tiz");
}
else
{
OutputIntTexCoordWrap(out, "wrapR", "depth", texCoordZ, "0", "tiz");
}
texCoordZ = "tiz";
} }
} }
...@@ -1421,7 +1484,8 @@ void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *built ...@@ -1421,7 +1484,8 @@ void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *built
} }
} }
if (textureFunction->offset) if (textureFunction->offset && (!IsIntegerSampler(textureFunction->sampler) ||
textureFunction->method == TextureFunction::FETCH))
{ {
out << ", offset"; out << ", offset";
} }
......
...@@ -337,8 +337,15 @@ void UniformHLSL::samplerMetadataUniforms(TInfoSinkBase &out, const char *reg) ...@@ -337,8 +337,15 @@ void UniformHLSL::samplerMetadataUniforms(TInfoSinkBase &out, const char *reg)
// If mSamplerRegister is 0 the shader doesn't use any textures. // If mSamplerRegister is 0 the shader doesn't use any textures.
if (mSamplerRegister > 0) if (mSamplerRegister > 0)
{ {
out << " int4 samplerMetadata[" << mSamplerRegister << "] : packoffset(" << reg out << " struct SamplerMetadata\n"
<< ");\n"; " {\n"
" int baseLevel;\n"
" int internalFormatBits;\n"
" int wrapModes;\n"
" int padding;\n"
" };\n"
" SamplerMetadata samplerMetadata["
<< mSamplerRegister << "] : packoffset(" << reg << ");\n";
} }
} }
......
...@@ -362,6 +362,22 @@ void GetTriFanIndices(const GLvoid *indices, ...@@ -362,6 +362,22 @@ void GetTriFanIndices(const GLvoid *indices,
} }
} }
int GetWrapBits(GLenum wrap)
{
switch (wrap)
{
case GL_CLAMP_TO_EDGE:
return 0x1;
case GL_REPEAT:
return 0x2;
case GL_MIRRORED_REPEAT:
return 0x3;
default:
UNREACHABLE();
return 0;
}
}
} // anonymous namespace } // anonymous namespace
Renderer11::Renderer11(egl::Display *display) Renderer11::Renderer11(egl::Display *display)
...@@ -1213,8 +1229,7 @@ gl::Error Renderer11::setSamplerState(gl::SamplerType type, ...@@ -1213,8 +1229,7 @@ gl::Error Renderer11::setSamplerState(gl::SamplerType type,
else UNREACHABLE(); else UNREACHABLE();
ASSERT(metadata != nullptr); ASSERT(metadata != nullptr);
metadata->update(index, texture->getBaseLevel(), metadata->update(index, *texture);
texture->getInternalFormat(texture->getTarget(), texture->getBaseLevel()));
return gl::Error(GL_NO_ERROR); return gl::Error(GL_NO_ERROR);
} }
...@@ -2354,21 +2369,21 @@ void Renderer11::SamplerMetadataD3D11::initData(unsigned int samplerCount) ...@@ -2354,21 +2369,21 @@ void Renderer11::SamplerMetadataD3D11::initData(unsigned int samplerCount)
mSamplerMetadata.resize(samplerCount); mSamplerMetadata.resize(samplerCount);
} }
void Renderer11::SamplerMetadataD3D11::update(unsigned int samplerIndex, void Renderer11::SamplerMetadataD3D11::update(unsigned int samplerIndex, const gl::Texture &texture)
unsigned int baseLevel,
GLenum internalFormat)
{ {
if (mSamplerMetadata[samplerIndex].parameters[0] != static_cast<int>(baseLevel)) unsigned int baseLevel = texture.getBaseLevel();
GLenum internalFormat = texture.getInternalFormat(texture.getTarget(), texture.getBaseLevel());
if (mSamplerMetadata[samplerIndex].baseLevel != static_cast<int>(baseLevel))
{ {
mSamplerMetadata[samplerIndex].parameters[0] = static_cast<int>(baseLevel); mSamplerMetadata[samplerIndex].baseLevel = static_cast<int>(baseLevel);
mDirty = true; mDirty = true;
} }
// internalFormatBits == 0 means a 32-bit texture in the case of integer textures. In the case // Some metadata is needed only for integer textures. We avoid updating the constant buffer
// of non-integer textures, internalFormatBits is meaningless. We avoid updating the constant // unnecessarily by changing the data only in case the texture is an integer texture and
// buffer unnecessarily by changing the data only in case the texture is an integer texture and // the values have changed.
// the value has changed. bool needIntegerTextureMetadata = false;
bool needInternalFormatBits = false; // internalFormatBits == 0 means a 32-bit texture in the case of integer textures.
int internalFormatBits = 0; int internalFormatBits = 0;
switch (internalFormat) switch (internalFormat)
{ {
...@@ -2380,7 +2395,7 @@ void Renderer11::SamplerMetadataD3D11::update(unsigned int samplerIndex, ...@@ -2380,7 +2395,7 @@ void Renderer11::SamplerMetadataD3D11::update(unsigned int samplerIndex,
case GL_RG32UI: case GL_RG32UI:
case GL_R32I: case GL_R32I:
case GL_R32UI: case GL_R32UI:
needInternalFormatBits = true; needIntegerTextureMetadata = true;
break; break;
case GL_RGBA16I: case GL_RGBA16I:
case GL_RGBA16UI: case GL_RGBA16UI:
...@@ -2390,7 +2405,7 @@ void Renderer11::SamplerMetadataD3D11::update(unsigned int samplerIndex, ...@@ -2390,7 +2405,7 @@ void Renderer11::SamplerMetadataD3D11::update(unsigned int samplerIndex,
case GL_RG16UI: case GL_RG16UI:
case GL_R16I: case GL_R16I:
case GL_R16UI: case GL_R16UI:
needInternalFormatBits = true; needIntegerTextureMetadata = true;
internalFormatBits = 16; internalFormatBits = 16;
break; break;
case GL_RGBA8I: case GL_RGBA8I:
...@@ -2401,21 +2416,34 @@ void Renderer11::SamplerMetadataD3D11::update(unsigned int samplerIndex, ...@@ -2401,21 +2416,34 @@ void Renderer11::SamplerMetadataD3D11::update(unsigned int samplerIndex,
case GL_RG8UI: case GL_RG8UI:
case GL_R8I: case GL_R8I:
case GL_R8UI: case GL_R8UI:
needInternalFormatBits = true; needIntegerTextureMetadata = true;
internalFormatBits = 8; internalFormatBits = 8;
break; break;
case GL_RGB10_A2UI: case GL_RGB10_A2UI:
needInternalFormatBits = true; needIntegerTextureMetadata = true;
internalFormatBits = 10; internalFormatBits = 10;
break; break;
default: default:
break; break;
} }
if (needInternalFormatBits && if (needIntegerTextureMetadata)
mSamplerMetadata[samplerIndex].parameters[1] != internalFormatBits)
{ {
mSamplerMetadata[samplerIndex].parameters[1] = internalFormatBits; if (mSamplerMetadata[samplerIndex].internalFormatBits != internalFormatBits)
mDirty = true; {
mSamplerMetadata[samplerIndex].internalFormatBits = internalFormatBits;
mDirty = true;
}
// Pack the wrap values into one integer so we can fit all the metadata in one 4-integer
// vector.
GLenum wrapS = texture.getWrapS();
GLenum wrapT = texture.getWrapT();
GLenum wrapR = texture.getWrapR();
int wrapModes = GetWrapBits(wrapS) | (GetWrapBits(wrapT) << 2) | (GetWrapBits(wrapR) << 4);
if (mSamplerMetadata[samplerIndex].wrapModes != wrapModes)
{
mSamplerMetadata[samplerIndex].wrapModes = wrapModes;
mDirty = true;
}
} }
} }
......
...@@ -350,11 +350,16 @@ class Renderer11 : public RendererD3D ...@@ -350,11 +350,16 @@ class Renderer11 : public RendererD3D
struct dx_SamplerMetadata struct dx_SamplerMetadata
{ {
int parameters[4]; int baseLevel;
int internalFormatBits;
int wrapModes;
int padding; // This just pads the struct to 16 bytes
}; };
static_assert(sizeof(dx_SamplerMetadata) == 16u,
"Sampler metadata struct must be one 4-vec / 16 bytes.");
void initData(unsigned int samplerCount); void initData(unsigned int samplerCount);
void update(unsigned int samplerIndex, unsigned int baseLevel, GLenum internalFormat); void update(unsigned int samplerIndex, const gl::Texture &texture);
const dx_SamplerMetadata *getData() const; const dx_SamplerMetadata *getData() const;
size_t sizeBytes() const; size_t sizeBytes() const;
......
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