Skip to content

Commit

Permalink
Implement more texture border color adjustments
Browse files Browse the repository at this point in the history
D3D11:
* Exposed EXT_texture_border_clamp extension string,
  to ensure that the relevant CTS tests are running.

* Updated StateManager11::setSamplerState to adjust
  the border color based on the texture format.

* Refactored ShaderConstants11::updateSamplerMetadata to
  correctly adjust the border color for integer formats.

* Removed unused SamplerMetadata.internalFormatBits

D3D9:
* Updated Renderer9::setSamplerState to adjust the border
  color value based on the current texture format.

* Added borderColorSrgb feature required for some drivers.

GL:
* Copy alpha value to green for A and LA legacy formats to
  workaround driver bugs when lumaWorkaround is not used.

Tests:
* Added ES 2.0 tests for texture formats
  that require border color adjustments.

Fixed: angleproject:7969
Change-Id: I3d36cce43e76e6d5069a51865152c2250ecbb017
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4291000
Commit-Queue: Alexey Knyazev <[email protected]>
Reviewed-by: Geoff Lang <[email protected]>
  • Loading branch information
lexaknyazev authored and Angle LUCI CQ committed Feb 28, 2023
1 parent 9ee816c commit a1f9b9a
Show file tree
Hide file tree
Showing 16 changed files with 392 additions and 110 deletions.
7 changes: 7 additions & 0 deletions include/platform/FeaturesD3D_autogen.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ struct FeaturesD3D : FeatureSetBase
FeaturesD3D();
~FeaturesD3D();

FeatureInfo borderColorSrgb = {
"borderColorSrgb",
FeatureCategory::D3DWorkarounds,
"Some drivers expect sRGB border color for sRGB texture formats",
&members,
};

FeatureInfo mrtPerfWorkaround = {
"mrtPerfWorkaround",
FeatureCategory::D3DWorkarounds,
Expand Down
7 changes: 7 additions & 0 deletions include/platform/d3d_features.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@
"d3d_features.json: Features and workarounds for D3D driver bugs and other issues."
],
"features": [
{
"name": "border_color_srgb",
"category": "Workarounds",
"description": [
"Some drivers expect sRGB border color for sRGB texture formats"
]
},
{
"name": "mrt_perf_workaround",
"category": "Workarounds",
Expand Down
8 changes: 4 additions & 4 deletions scripts/code_generation_hashes/ANGLE_features.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"include/platform/FeaturesD3D_autogen.h":
"256cd7175aa885e9ec57ecb86d455fc4",
"bdce5cac5c70e04fd39e9cf8c6969292",
"include/platform/FeaturesGL_autogen.h":
"38325ab28fca006d06f46d1ad4ad2d63",
"include/platform/FeaturesMtl_autogen.h":
Expand All @@ -10,7 +10,7 @@
"include/platform/FrontendFeatures_autogen.h":
"be41034e621326dd51e86b139705ea39",
"include/platform/d3d_features.json":
"0d316218a4ac7c3bb9692e7525216973",
"c3f7694511855304b3f678a6ad461d1e",
"include/platform/frontend_features.json":
"c2ace937cdaa65aedb66e7be5e5b761d",
"include/platform/gen_features.py":
Expand All @@ -22,7 +22,7 @@
"include/platform/vk_features.json":
"c9803deadd5de3a14ea1d28bcb79c41d",
"util/angle_features_autogen.cpp":
"4729e51e6b6fe4f5822317d0065252e9",
"bc601b60e09aa77fd8d216b5c90fdb2f",
"util/angle_features_autogen.h":
"de8ee87450e3fe4ff15820564912d156"
"8089c076f65737fb66257e4d71923f30"
}
3 changes: 1 addition & 2 deletions src/compiler/translator/ResourcesHLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -675,9 +675,8 @@ void ResourcesHLSL::samplerMetadataUniforms(TInfoSinkBase &out, unsigned int reg
out << " struct SamplerMetadata\n"
" {\n"
" int baseLevel;\n"
" int internalFormatBits;\n"
" int wrapModes;\n"
" int padding;\n"
" int2 padding;\n"
" int4 intBorderColor;\n"
" };\n"
" SamplerMetadata samplerMetadata["
Expand Down
6 changes: 6 additions & 0 deletions src/libANGLE/angletypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,12 @@ class SamplerState final

bool setWrapR(GLenum wrapR);

bool usesBorderColor() const
{
return mWrapS == GL_CLAMP_TO_BORDER || mWrapT == GL_CLAMP_TO_BORDER ||
mWrapR == GL_CLAMP_TO_BORDER;
}

float getMaxAnisotropy() const { return mMaxAnisotropy; }

bool setMaxAnisotropy(float maxAnisotropy);
Expand Down
13 changes: 4 additions & 9 deletions src/libANGLE/renderer/d3d/d3d11/RenderStateCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -287,15 +287,10 @@ angle::Result RenderStateCache::getSamplerState(const gl::Context *context,
samplerDesc.MaxAnisotropy =
gl_d3d11::ConvertMaxAnisotropy(samplerState.getMaxAnisotropy(), featureLevel);
samplerDesc.ComparisonFunc = gl_d3d11::ConvertComparison(samplerState.getCompareFunc());
angle::ColorF borderColor;
if (samplerState.getBorderColor().type == angle::ColorGeneric::Type::Float)
{
borderColor = samplerState.getBorderColor().colorF;
}
samplerDesc.BorderColor[0] = borderColor.red;
samplerDesc.BorderColor[1] = borderColor.green;
samplerDesc.BorderColor[2] = borderColor.blue;
samplerDesc.BorderColor[3] = borderColor.alpha;
samplerDesc.BorderColor[0] = samplerState.getBorderColor().colorF.red;
samplerDesc.BorderColor[1] = samplerState.getBorderColor().colorF.green;
samplerDesc.BorderColor[2] = samplerState.getBorderColor().colorF.blue;
samplerDesc.BorderColor[3] = samplerState.getBorderColor().colorF.alpha;
samplerDesc.MinLOD = samplerState.getMinLod();
samplerDesc.MaxLOD = samplerState.getMaxLod();

Expand Down
144 changes: 69 additions & 75 deletions src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,6 @@ bool ShaderConstants11::updateSamplerMetadata(SamplerMetadata *data,
gl::TextureTarget target = (texture.getType() == gl::TextureType::CubeMap)
? gl::kCubeMapTextureTargetMin
: gl::NonCubeTextureTypeToTarget(texture.getType());
GLenum sizedFormat = texture.getFormat(target, baseLevel).info->sizedInternalFormat;
if (data->baseLevel != static_cast<int>(baseLevel))
{
data->baseLevel = static_cast<int>(baseLevel);
Expand All @@ -366,81 +365,52 @@ bool ShaderConstants11::updateSamplerMetadata(SamplerMetadata *data,
// Some metadata is needed only for integer textures. We avoid updating the constant buffer
// unnecessarily by changing the data only in case the texture is an integer texture and
// the values have changed.
bool needIntegerTextureMetadata = false;
// internalFormatBits == 0 means a 32-bit texture in the case of integer textures.
int internalFormatBits = 0;
switch (sizedFormat)
{
case GL_RGBA32I:
case GL_RGBA32UI:
case GL_RGB32I:
case GL_RGB32UI:
case GL_RG32I:
case GL_RG32UI:
case GL_R32I:
case GL_R32UI:
needIntegerTextureMetadata = true;
break;
case GL_RGBA16I:
case GL_RGBA16UI:
case GL_RGB16I:
case GL_RGB16UI:
case GL_RG16I:
case GL_RG16UI:
case GL_R16I:
case GL_R16UI:
needIntegerTextureMetadata = true;
internalFormatBits = 16;
break;
case GL_RGBA8I:
case GL_RGBA8UI:
case GL_RGB8I:
case GL_RGB8UI:
case GL_RG8I:
case GL_RG8UI:
case GL_R8I:
case GL_R8UI:
needIntegerTextureMetadata = true;
internalFormatBits = 8;
break;
case GL_RGB10_A2UI:
needIntegerTextureMetadata = true;
internalFormatBits = 10;
break;
default:
break;
const gl::InternalFormat &info = *texture.getFormat(target, baseLevel).info;
if (!info.isInt() && !texture.getState().isStencilMode())
{
return dirty;
}
if (needIntegerTextureMetadata)

// Pack the wrap values into one integer so we can fit all the metadata in two 4-integer
// vectors.
const GLenum wrapS = samplerState.getWrapS();
const GLenum wrapT = samplerState.getWrapT();
const GLenum wrapR = samplerState.getWrapR();
const int wrapModes =
GetWrapBits(wrapS) | (GetWrapBits(wrapT) << 2) | (GetWrapBits(wrapR) << 4);
if (data->wrapModes != wrapModes)
{
if (data->internalFormatBits != internalFormatBits)
{
data->internalFormatBits = internalFormatBits;
dirty = true;
}
// Pack the wrap values into one integer so we can fit all the metadata in two 4-integer
// vectors.
GLenum wrapS = samplerState.getWrapS();
GLenum wrapT = samplerState.getWrapT();
GLenum wrapR = samplerState.getWrapR();
int wrapModes = GetWrapBits(wrapS) | (GetWrapBits(wrapT) << 2) | (GetWrapBits(wrapR) << 4);
if (data->wrapModes != wrapModes)
{
data->wrapModes = wrapModes;
dirty = true;
}
data->wrapModes = wrapModes;
dirty = true;
}

const angle::ColorGeneric &borderColor(samplerState.getBorderColor());
constexpr int kBlack[4] = {};
const void *const intBorderColor = (borderColor.type == angle::ColorGeneric::Type::Float)
? kBlack
: borderColor.colorI.data();
ASSERT(static_cast<const void *>(borderColor.colorI.data()) ==
static_cast<const void *>(borderColor.colorUI.data()));
if (memcmp(data->intBorderColor, intBorderColor, sizeof(data->intBorderColor)) != 0)
{
memcpy(data->intBorderColor, intBorderColor, sizeof(data->intBorderColor));
dirty = true;
}
// Skip checking and syncing integer border color if it is not used
if (wrapS != GL_CLAMP_TO_BORDER && wrapT != GL_CLAMP_TO_BORDER && wrapR != GL_CLAMP_TO_BORDER)
{
return dirty;
}

// Use the sampler state border color only if it is integer, initialize to zeros otherwise
angle::ColorGeneric borderColor;
ASSERT(borderColor.colorI.red == 0 && borderColor.colorI.green == 0 &&
borderColor.colorI.blue == 0 && borderColor.colorI.alpha == 0);
if (samplerState.getBorderColor().type != angle::ColorGeneric::Type::Float)
{
borderColor = samplerState.getBorderColor();
}

// Adjust the border color value to the texture format
borderColor = AdjustBorderColor<false>(
borderColor,
angle::Format::Get(angle::Format::InternalFormatToID(info.sizedInternalFormat)),
texture.getState().isStencilMode());

ASSERT(static_cast<const void *>(borderColor.colorI.data()) ==
static_cast<const void *>(borderColor.colorUI.data()));
if (memcmp(data->intBorderColor, borderColor.colorI.data(), sizeof(data->intBorderColor)) != 0)
{
memcpy(data->intBorderColor, borderColor.colorI.data(), sizeof(data->intBorderColor));
dirty = true;
}

return dirty;
Expand Down Expand Up @@ -2694,11 +2664,35 @@ angle::Result StateManager11::setSamplerState(const gl::Context *context,

ASSERT(index < mRenderer->getNativeCaps().maxShaderTextureImageUnits[type]);

if (mForceSetShaderSamplerStates[type][index] ||
// When border color is used, its value may need to be readjusted based on the texture format.
const bool usesBorderColor = samplerState.usesBorderColor();

if (mForceSetShaderSamplerStates[type][index] || usesBorderColor ||
memcmp(&samplerState, &mCurShaderSamplerStates[type][index], sizeof(gl::SamplerState)) != 0)
{
// When clamp-to-border mode is used and a floating-point border color is set, the color
// value must be adjusted based on the texture format. Reset it to zero in all other cases
// to reduce the number of cached sampler entries. Address modes for integer texture
// formats are emulated in shaders and do not rely on this state.
angle::ColorGeneric borderColor;
if (usesBorderColor)
{
if (samplerState.getBorderColor().type == angle::ColorGeneric::Type::Float)
{
borderColor = samplerState.getBorderColor();
}
const uint32_t baseLevel = texture->getTextureState().getEffectiveBaseLevel();
const gl::TextureTarget target = TextureTypeToTarget(texture->getType(), 0);
const angle::Format &format = angle::Format::Get(angle::Format::InternalFormatToID(
texture->getFormat(target, baseLevel).info->sizedInternalFormat));

borderColor = AdjustBorderColor<false>(borderColor, format, false);
}
gl::SamplerState adjustedSamplerState(samplerState);
adjustedSamplerState.setBorderColor(borderColor.colorF);

ID3D11SamplerState *dxSamplerState = nullptr;
ANGLE_TRY(mRenderer->getSamplerState(context, samplerState, &dxSamplerState));
ANGLE_TRY(mRenderer->getSamplerState(context, adjustedSamplerState, &dxSamplerState));

ASSERT(dxSamplerState != nullptr);

Expand Down
7 changes: 2 additions & 5 deletions src/libANGLE/renderer/d3d/d3d11/StateManager11.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,14 +140,11 @@ class ShaderConstants11 : angle::NonCopyable

struct SamplerMetadata
{
SamplerMetadata()
: baseLevel(0), internalFormatBits(0), wrapModes(0), padding(0), intBorderColor{0}
{}
SamplerMetadata() : baseLevel(0), wrapModes(0), padding{0}, intBorderColor{0} {}

int baseLevel;
int internalFormatBits;
int wrapModes;
int padding; // This just pads the struct to 32 bytes
int padding[2]; // This just pads the struct to 32 bytes
int intBorderColor[4];
};

Expand Down
1 change: 1 addition & 0 deletions src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1677,6 +1677,7 @@ void GenerateCaps(ID3D11Device *device,
((extensions->multiviewOVR || extensions->multiview2OVR) &&
extensions->textureStorageMultisample2dArrayOES);
extensions->copyTexture3dANGLE = true;
extensions->textureBorderClampEXT = true;
extensions->textureBorderClampOES = true;
extensions->multiDrawIndirectEXT = true;
extensions->textureMultisampleANGLE = true;
Expand Down
57 changes: 48 additions & 9 deletions src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ Renderer9::Renderer9(egl::Display *display) : RendererD3D(display), mStateManage

const egl::AttributeMap &attributes = display->getAttributeMap();
EGLint requestedDeviceType = static_cast<EGLint>(attributes.get(
EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE));
EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE));
switch (requestedDeviceType)
{
case EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE:
Expand Down Expand Up @@ -564,7 +564,7 @@ egl::ConfigSet Renderer9::generateConfigs()
config.transparentGreenValue = 0;
config.transparentBlueValue = 0;
config.colorComponentType = gl_egl::GLComponentTypeToEGLColorComponentType(
colorBufferFormatInfo.componentType);
colorBufferFormatInfo.componentType);

configs.add(config);
}
Expand Down Expand Up @@ -1026,13 +1026,52 @@ angle::Result Renderer9::setSamplerState(const gl::Context *context,
mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXANISOTROPY, maxAnisotropy);
}

const bool isSrgb = gl::GetSizedInternalFormatInfo(textureD3D->getBaseLevelInternalFormat())
.colorEncoding == GL_SRGB;
mDevice->SetSamplerState(d3dSampler, D3DSAMP_SRGBTEXTURE, isSrgb);
const gl::InternalFormat &info =
gl::GetSizedInternalFormatInfo(textureD3D->getBaseLevelInternalFormat());

ASSERT(texture->getBorderColor().type == angle::ColorGeneric::Type::Float);
mDevice->SetSamplerState(d3dSampler, D3DSAMP_BORDERCOLOR,
gl_d3d9::ConvertColor(texture->getBorderColor().colorF));
mDevice->SetSamplerState(d3dSampler, D3DSAMP_SRGBTEXTURE, info.colorEncoding == GL_SRGB);

if (samplerState.usesBorderColor())
{
angle::ColorGeneric borderColor = texture->getBorderColor();
ASSERT(borderColor.type == angle::ColorGeneric::Type::Float);

// Enforce opaque alpha for opaque formats, excluding DXT1 RGBA as it has no bits info.
if (info.alphaBits == 0 && info.componentCount < 4)
{
borderColor.colorF.alpha = 1.0f;
}

if (info.isLUMA())
{
if (info.luminanceBits == 0)
{
borderColor.colorF.red = 0.0f;
}
// Older Intel drivers use RGBA border color when sampling from D3DFMT_A8L8.
// However, some recent Intel drivers sample alpha from green border channel
// when using this format. Assume the old behavior because newer GPUs should
// use D3D11 anyway.
borderColor.colorF.green = borderColor.colorF.red;
borderColor.colorF.blue = borderColor.colorF.red;
}

D3DCOLOR d3dBorderColor;
if (info.colorEncoding == GL_SRGB && getFeatures().borderColorSrgb.enabled)
{
d3dBorderColor =
D3DCOLOR_RGBA(gl::linearToSRGB(gl::clamp01(borderColor.colorF.red)),
gl::linearToSRGB(gl::clamp01(borderColor.colorF.green)),
gl::linearToSRGB(gl::clamp01(borderColor.colorF.blue)),
gl::unorm<8>(borderColor.colorF.alpha));
}
else
{
d3dBorderColor = gl_d3d9::ConvertColor(borderColor.colorF);
}

mDevice->SetSamplerState(d3dSampler, D3DSAMP_BORDERCOLOR, d3dBorderColor);
}
}

appliedSampler.forceSet = false;
Expand Down Expand Up @@ -3062,7 +3101,7 @@ void Renderer9::initializeFeatures(angle::FeaturesD3D *features) const
{
if (!mDisplay->getState().featuresAllDisabled)
{
d3d9::InitializeFeatures(features);
d3d9::InitializeFeatures(features, mAdapterIdentifier.VendorId);
}
ApplyFeatureOverrides(features, mDisplay->getState());
}
Expand Down
Loading

0 comments on commit a1f9b9a

Please sign in to comment.