зеркало из https://github.com/AvaloniaUI/angle.git
Vulkan: Implement EXT_texture_sRGB_decode
Implement EXT_texture_sRGB_decode. This builds on the existing functionality from EXT_texture_sRGB_override, with 2 major edge cases: 1. sRGB_decode allows the texture state to be overridden by sampler state, which is implemented by forcing a a texture state sync during updateActiveTextures if a texture is bound to the same unit as a sampler with that state 2. texelFetch calls require us to reenable decoding, regardless of decode state. We add a new compiler pass (FlagSamplersWithTexelFetch) to mark samplers that are used with texelFetch in order to support this. This change also re-enables EXT_texture_sRGB_R8, which was disabled due to a dEQP bug that this change will bypass. Bug: angleproject:3609 Bug: angleproject:4503 Test: dEQP.GLES31/functional_srgb_texture_decode_skip_decode_* Test: GLES31/functional_state_query_texture_*_srgb_decode_* Test: GLES31/functional_state_query_sampler_*_srgb_decode_* Test: GLES31/functional_debug_negative_coverage_*_srgb_decode_* Test: GLES31/functional_android_extension_pack_extensions_ext_texture_srgb_decode Test: angle_end2end_tests --gtest_filter=SRGBTextureTest.*Vulkan* Change-Id: I4a67e487dc82e2f57c8c87d4bcd8ef442b6fe220 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2359481 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: Jamie Madill <jmadill@chromium.org> Reviewed-by: Tim Van Patten <timvp@google.com>
This commit is contained in:
Родитель
e3a573811a
Коммит
7bbe497aa8
|
@ -200,6 +200,9 @@ struct ShaderVariable
|
|||
// Deprecated version of isSameVaryingAtLinkTime, which assumes ESSL1.
|
||||
bool isSameVaryingAtLinkTime(const ShaderVariable &other) const;
|
||||
|
||||
// If the variable is a sampler that has ever been statically used with texelFetch
|
||||
bool texelFetchInvoked;
|
||||
|
||||
protected:
|
||||
bool isSameVariableAtLinkTime(const ShaderVariable &other,
|
||||
bool matchPrecision,
|
||||
|
|
|
@ -223,12 +223,19 @@ const char *GetDebugMessageTypeString(GLenum type);
|
|||
const char *GetDebugMessageSeverityString(GLenum severity);
|
||||
|
||||
// For use with EXT_texture_format_sRGB_override and EXT_texture_sRGB_decode
|
||||
// A texture may either have SRGB decoding forced on, or use whatever decode state is default for
|
||||
// the texture format.
|
||||
// A texture may be forced to decode to a nonlinear colorspace, to a linear colorspace, or to the
|
||||
// default colorspace of its current format.
|
||||
//
|
||||
// Default corresponds to "the texture should use the imageview that corresponds to its format"
|
||||
// Linear corresponds to "the texture has sRGB decoding disabled by extension, and should use a
|
||||
// linear imageview even if it is in a nonlinear format" NonLinear corresponds to "the texture has
|
||||
// sRGB override enabled by extension, and should use a nonlinear imageview even if it is in a
|
||||
// linear format"
|
||||
enum class SrgbOverride
|
||||
{
|
||||
Default = 0,
|
||||
Enabled
|
||||
Linear,
|
||||
NonLinear
|
||||
};
|
||||
|
||||
} // namespace gl
|
||||
|
|
|
@ -134,6 +134,8 @@ angle_translator_sources = [
|
|||
"src/compiler/translator/tree_ops/EmulatePrecision.h",
|
||||
"src/compiler/translator/tree_ops/ExpandIntegerPowExpressions.cpp",
|
||||
"src/compiler/translator/tree_ops/ExpandIntegerPowExpressions.h",
|
||||
"src/compiler/translator/tree_ops/FlagSamplersWithTexelFetch.cpp",
|
||||
"src/compiler/translator/tree_ops/FlagSamplersWithTexelFetch.h",
|
||||
"src/compiler/translator/tree_ops/FoldExpressions.cpp",
|
||||
"src/compiler/translator/tree_ops/FoldExpressions.h",
|
||||
"src/compiler/translator/tree_ops/InitializeVariables.cpp",
|
||||
|
|
|
@ -48,6 +48,7 @@ ShaderVariable::ShaderVariable(GLenum typeIn)
|
|||
index(-1),
|
||||
interpolation(INTERPOLATION_SMOOTH),
|
||||
isInvariant(false),
|
||||
texelFetchInvoked(false),
|
||||
flattenedOffsetInParentArrays(-1)
|
||||
{}
|
||||
|
||||
|
@ -79,6 +80,7 @@ ShaderVariable::ShaderVariable(const ShaderVariable &other)
|
|||
index(other.index),
|
||||
interpolation(other.interpolation),
|
||||
isInvariant(other.isInvariant),
|
||||
texelFetchInvoked(other.texelFetchInvoked),
|
||||
flattenedOffsetInParentArrays(other.flattenedOffsetInParentArrays)
|
||||
{}
|
||||
|
||||
|
@ -104,6 +106,7 @@ ShaderVariable &ShaderVariable::operator=(const ShaderVariable &other)
|
|||
index = other.index;
|
||||
interpolation = other.interpolation;
|
||||
isInvariant = other.isInvariant;
|
||||
texelFetchInvoked = other.texelFetchInvoked;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -117,7 +120,7 @@ bool ShaderVariable::operator==(const ShaderVariable &other) const
|
|||
binding != other.binding || imageUnitFormat != other.imageUnitFormat ||
|
||||
offset != other.offset || readonly != other.readonly || writeonly != other.writeonly ||
|
||||
index != other.index || interpolation != other.interpolation ||
|
||||
isInvariant != other.isInvariant)
|
||||
isInvariant != other.isInvariant || texelFetchInvoked != other.texelFetchInvoked)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "compiler/translator/ImmutableStringBuilder.h"
|
||||
#include "compiler/translator/OutputVulkanGLSL.h"
|
||||
#include "compiler/translator/StaticType.h"
|
||||
#include "compiler/translator/tree_ops/FlagSamplersWithTexelFetch.h"
|
||||
#include "compiler/translator/tree_ops/NameEmbeddedUniformStructs.h"
|
||||
#include "compiler/translator/tree_ops/RemoveAtomicCounterBuiltins.h"
|
||||
#include "compiler/translator/tree_ops/RemoveInactiveInterfaceVariables.h"
|
||||
|
@ -848,6 +849,11 @@ bool TranslatorVulkan::translateImpl(TIntermBlock *root,
|
|||
}
|
||||
}
|
||||
|
||||
if (!FlagSamplersForTexelFetch(this, root, &getSymbolTable(), &mUniforms))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (defaultUniformCount > 0)
|
||||
{
|
||||
gl::ShaderType shaderType = gl::FromGLenum<gl::ShaderType>(getShaderType());
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
//
|
||||
// Copyright 2020 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.
|
||||
//
|
||||
// FlagSamplersForTexelFetch.cpp: finds all instances of texelFetch used with a static reference to
|
||||
// a sampler uniform, and flag that uniform as having been used with texelFetch
|
||||
//
|
||||
|
||||
#include "compiler/translator/tree_ops/FlagSamplersWithTexelFetch.h"
|
||||
|
||||
#include "angle_gl.h"
|
||||
#include "common/utilities.h"
|
||||
|
||||
#include "compiler/translator/SymbolTable.h"
|
||||
#include "compiler/translator/tree_util/IntermNode_util.h"
|
||||
#include "compiler/translator/tree_util/IntermTraverse.h"
|
||||
#include "compiler/translator/tree_util/ReplaceVariable.h"
|
||||
|
||||
namespace sh
|
||||
{
|
||||
namespace
|
||||
{
|
||||
|
||||
// gvec4 texelFetch(gsamplerXD sampler, ivecX P, int lod)
|
||||
constexpr uint32_t kTexelFetchSequenceLength = 3u;
|
||||
|
||||
// gvec4 texelFetchOffset(gsamplerXD sampler, ivecX P, int lod, ivecX offset)
|
||||
constexpr uint32_t kTexelFetchOffsetSequenceLength = 4u;
|
||||
|
||||
class FlagSamplersWithTexelFetchTraverser : public TIntermTraverser
|
||||
{
|
||||
public:
|
||||
FlagSamplersWithTexelFetchTraverser(TSymbolTable *symbolTable,
|
||||
std::vector<ShaderVariable> *uniforms)
|
||||
: TIntermTraverser(true, true, true, symbolTable), mUniforms(uniforms)
|
||||
{}
|
||||
|
||||
bool visitAggregate(Visit visit, TIntermAggregate *node) override
|
||||
{
|
||||
// Decide if the node is a call to texelFetch[Offset]
|
||||
if (node->getOp() != EOpCallBuiltInFunction)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
ASSERT(node->getFunction()->symbolType() == SymbolType::BuiltIn);
|
||||
if (node->getFunction()->name() != "texelFetch" &&
|
||||
node->getFunction()->name() != "texelFetchOffset")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
const TIntermSequence *sequence = node->getSequence();
|
||||
|
||||
// This must be a valid texelFetch invokation with the required number of arguments
|
||||
ASSERT(sequence->size() == (node->getFunction()->name() == "texelFetch"
|
||||
? kTexelFetchSequenceLength
|
||||
: kTexelFetchOffsetSequenceLength));
|
||||
|
||||
TIntermSymbol *samplerSymbol = sequence->at(0)->getAsSymbolNode();
|
||||
ASSERT(samplerSymbol != nullptr);
|
||||
|
||||
const TVariable &samplerVariable = samplerSymbol->variable();
|
||||
|
||||
for (ShaderVariable &uniform : *mUniforms)
|
||||
{
|
||||
if (samplerVariable.name() == uniform.name)
|
||||
{
|
||||
ASSERT(gl::IsSamplerType(uniform.type));
|
||||
uniform.texelFetchInvoked = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<ShaderVariable> *mUniforms;
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
bool FlagSamplersForTexelFetch(TCompiler *compiler,
|
||||
TIntermBlock *root,
|
||||
TSymbolTable *symbolTable,
|
||||
std::vector<ShaderVariable> *uniforms)
|
||||
{
|
||||
ASSERT(uniforms != nullptr);
|
||||
if (uniforms->size() > 0)
|
||||
{
|
||||
FlagSamplersWithTexelFetchTraverser traverser(symbolTable, uniforms);
|
||||
root->traverse(&traverser);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace sh
|
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// Copyright 2020 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.
|
||||
//
|
||||
// FlagSamplersForTexelFetch.h: finds all instances of texelFetch used with a static reference to a
|
||||
// sampler uniform, and flag that uniform as having been used with texelFetch
|
||||
//
|
||||
|
||||
#ifndef COMPILER_TRANSLATOR_TREEOPS_FLAGSAMPLERSWITHTEXELFETCH_H_
|
||||
#define COMPILER_TRANSLATOR_TREEOPS_FLAGSAMPLERSWITHTEXELFETCH_H_
|
||||
|
||||
#include "GLSLANG/ShaderVars.h"
|
||||
#include "common/angleutils.h"
|
||||
|
||||
namespace sh
|
||||
{
|
||||
class TCompiler;
|
||||
class TIntermBlock;
|
||||
class TSymbolTable;
|
||||
|
||||
// This flags all samplers which are statically accessed by a texelFetch invokation- that is, the
|
||||
// sampler is used as a direct argument to the call to texelFetch. Dynamic accesses, or accesses
|
||||
// with any amount of indirection, are not counted.
|
||||
ANGLE_NO_DISCARD bool FlagSamplersForTexelFetch(TCompiler *compiler,
|
||||
TIntermBlock *root,
|
||||
TSymbolTable *symbolTable,
|
||||
std::vector<sh::ShaderVariable> *uniforms);
|
||||
} // namespace sh
|
||||
|
||||
#endif // COMPILER_TRANSLATOR_TREEOPS_FLAGSAMPLERSWITHTEXELFETCH_H_
|
|
@ -5611,7 +5611,7 @@ void Context::texImage2DExternal(TextureTarget target,
|
|||
void Context::invalidateTexture(TextureType target)
|
||||
{
|
||||
mImplementation->invalidateTexture(target);
|
||||
mState.invalidateTexture(target);
|
||||
mState.invalidateTextureBindings(target);
|
||||
}
|
||||
|
||||
void Context::getMultisamplefv(GLenum pname, GLuint index, GLfloat *val)
|
||||
|
|
|
@ -889,6 +889,7 @@ void WriteShaderVar(BinaryOutputStream *stream, const sh::ShaderVariable &var)
|
|||
stream->writeInt(var.offset);
|
||||
stream->writeInt(var.readonly);
|
||||
stream->writeInt(var.writeonly);
|
||||
stream->writeInt(var.texelFetchInvoked);
|
||||
|
||||
ASSERT(var.fields.empty());
|
||||
}
|
||||
|
@ -906,10 +907,11 @@ void LoadShaderVar(BinaryInputStream *stream, sh::ShaderVariable *var)
|
|||
var->structName = stream->readString();
|
||||
var->setParentArrayIndex(stream->readInt<int>());
|
||||
|
||||
var->imageUnitFormat = stream->readInt<GLenum>();
|
||||
var->offset = stream->readInt<int>();
|
||||
var->readonly = stream->readBool();
|
||||
var->writeonly = stream->readBool();
|
||||
var->imageUnitFormat = stream->readInt<GLenum>();
|
||||
var->offset = stream->readInt<int>();
|
||||
var->readonly = stream->readBool();
|
||||
var->writeonly = stream->readBool();
|
||||
var->texelFetchInvoked = stream->readBool();
|
||||
}
|
||||
|
||||
// VariableLocation implementation.
|
||||
|
|
|
@ -469,10 +469,11 @@ class FlattenUniformVisitor : public sh::VariableNameVisitor
|
|||
LinkedUniform linkedUniform(variable.type, variable.precision, fullNameWithArrayIndex,
|
||||
variable.arraySizes, getBinding(), getOffset(), mLocation,
|
||||
-1, sh::kDefaultBlockMemberInfo);
|
||||
linkedUniform.mappedName = fullMappedNameWithArrayIndex;
|
||||
linkedUniform.active = mMarkActive;
|
||||
linkedUniform.staticUse = mMarkStaticUse;
|
||||
linkedUniform.outerArraySizes = arraySizes;
|
||||
linkedUniform.mappedName = fullMappedNameWithArrayIndex;
|
||||
linkedUniform.active = mMarkActive;
|
||||
linkedUniform.staticUse = mMarkStaticUse;
|
||||
linkedUniform.outerArraySizes = arraySizes;
|
||||
linkedUniform.texelFetchInvoked = variable.texelFetchInvoked;
|
||||
if (variable.hasParentArrayIndex())
|
||||
{
|
||||
linkedUniform.setParentArrayIndex(variable.parentArrayIndex());
|
||||
|
|
|
@ -1549,7 +1549,7 @@ void State::initializeZeroTextures(const Context *context, const TextureMap &zer
|
|||
}
|
||||
}
|
||||
|
||||
void State::invalidateTexture(TextureType type)
|
||||
void State::invalidateTextureBindings(TextureType type)
|
||||
{
|
||||
mDirtyBits.set(DIRTY_BIT_TEXTURE_BINDINGS);
|
||||
}
|
||||
|
|
|
@ -307,7 +307,7 @@ class State : angle::NonCopyable
|
|||
void detachTexture(const Context *context, const TextureMap &zeroTextures, TextureID texture);
|
||||
void initializeZeroTextures(const Context *context, const TextureMap &zeroTextures);
|
||||
|
||||
void invalidateTexture(TextureType type);
|
||||
void invalidateTextureBindings(TextureType type);
|
||||
|
||||
// Sampler object binding manipulation
|
||||
void setSamplerBinding(const Context *context, GLuint textureUnit, Sampler *sampler);
|
||||
|
|
|
@ -893,7 +893,7 @@ void Texture::setSRGBOverride(const Context *context, GLenum sRGBOverride)
|
|||
{
|
||||
SrgbOverride oldOverride = mState.mSrgbOverride;
|
||||
mState.mSrgbOverride =
|
||||
(sRGBOverride == GL_SRGB) ? SrgbOverride::Enabled : SrgbOverride::Default;
|
||||
(sRGBOverride == GL_SRGB) ? SrgbOverride::NonLinear : SrgbOverride::Default;
|
||||
if (mState.mSrgbOverride != oldOverride)
|
||||
{
|
||||
signalDirtyState(DIRTY_BIT_SRGB_OVERRIDE);
|
||||
|
@ -902,7 +902,7 @@ void Texture::setSRGBOverride(const Context *context, GLenum sRGBOverride)
|
|||
|
||||
GLenum Texture::getSRGBOverride() const
|
||||
{
|
||||
return (mState.mSrgbOverride == SrgbOverride::Enabled) ? GL_SRGB : GL_NONE;
|
||||
return (mState.mSrgbOverride == SrgbOverride::NonLinear) ? GL_SRGB : GL_NONE;
|
||||
}
|
||||
|
||||
const SamplerState &Texture::getSamplerState() const
|
||||
|
|
|
@ -597,6 +597,7 @@ void SerializeShaderVariable(gl::BinaryOutputStream *bos, const sh::ShaderVariab
|
|||
bos->writeInt(shaderVariable.index);
|
||||
bos->writeEnum(shaderVariable.interpolation);
|
||||
bos->writeInt(shaderVariable.isInvariant);
|
||||
bos->writeInt(shaderVariable.texelFetchInvoked);
|
||||
}
|
||||
|
||||
void SerializeShaderVariablesVector(gl::BinaryOutputStream *bos,
|
||||
|
|
|
@ -51,6 +51,7 @@ struct Format final : private angle::NonCopyable
|
|||
|
||||
constexpr bool hasDepthOrStencilBits() const;
|
||||
constexpr bool isLUMA() const;
|
||||
constexpr bool isSRGB() const;
|
||||
|
||||
constexpr bool isSint() const;
|
||||
constexpr bool isUint() const;
|
||||
|
@ -185,6 +186,40 @@ constexpr bool Format::isLUMA() const
|
|||
return redBits == 0 && (luminanceBits > 0 || alphaBits > 0);
|
||||
}
|
||||
|
||||
constexpr bool Format::isSRGB() const
|
||||
{
|
||||
// R8G8_UNORM_SRGB and B8G8R8_UNORM_SRGB are not yet supported by ANGLE
|
||||
// clang-format off
|
||||
return
|
||||
id == FormatID::R8_UNORM_SRGB ||
|
||||
id == FormatID::R8G8B8_UNORM_SRGB ||
|
||||
id == FormatID::R8G8B8A8_UNORM_SRGB ||
|
||||
id == FormatID::B8G8R8A8_UNORM_SRGB ||
|
||||
id == FormatID::BC1_RGB_UNORM_SRGB_BLOCK ||
|
||||
id == FormatID::BC1_RGBA_UNORM_SRGB_BLOCK ||
|
||||
id == FormatID::BC2_RGBA_UNORM_SRGB_BLOCK ||
|
||||
id == FormatID::BC3_RGBA_UNORM_SRGB_BLOCK ||
|
||||
id == FormatID::BPTC_SRGB_ALPHA_UNORM_BLOCK ||
|
||||
id == FormatID::ETC2_R8G8B8_SRGB_BLOCK ||
|
||||
id == FormatID::ETC2_R8G8B8A1_SRGB_BLOCK ||
|
||||
id == FormatID::ETC2_R8G8B8A8_SRGB_BLOCK ||
|
||||
id == FormatID::ASTC_4x4_SRGB_BLOCK ||
|
||||
id == FormatID::ASTC_5x4_SRGB_BLOCK ||
|
||||
id == FormatID::ASTC_5x5_SRGB_BLOCK ||
|
||||
id == FormatID::ASTC_6x5_SRGB_BLOCK ||
|
||||
id == FormatID::ASTC_6x6_SRGB_BLOCK ||
|
||||
id == FormatID::ASTC_8x5_SRGB_BLOCK ||
|
||||
id == FormatID::ASTC_8x6_SRGB_BLOCK ||
|
||||
id == FormatID::ASTC_8x8_SRGB_BLOCK ||
|
||||
id == FormatID::ASTC_10x5_SRGB_BLOCK ||
|
||||
id == FormatID::ASTC_10x6_SRGB_BLOCK ||
|
||||
id == FormatID::ASTC_10x8_SRGB_BLOCK ||
|
||||
id == FormatID::ASTC_10x10_SRGB_BLOCK ||
|
||||
id == FormatID::ASTC_12x10_SRGB_BLOCK ||
|
||||
id == FormatID::ASTC_12x12_SRGB_BLOCK;
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
constexpr bool Format::isSint() const
|
||||
{
|
||||
return componentType == GL_INT;
|
||||
|
|
|
@ -730,7 +730,7 @@ ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk
|
|||
mGraphicsDirtyBits = mNewGraphicsCommandBufferDirtyBits;
|
||||
mComputeDirtyBits = mNewComputeCommandBufferDirtyBits;
|
||||
|
||||
mActiveTextures.fill({nullptr, nullptr});
|
||||
mActiveTextures.fill({nullptr, nullptr, true});
|
||||
mActiveImages.fill(nullptr);
|
||||
|
||||
mPipelineDirtyBitsMask.set();
|
||||
|
@ -4105,14 +4105,28 @@ angle::Result ContextVk::updateActiveTextures(const gl::Context *context)
|
|||
TextureVk *textureVk = vk::GetImpl(texture);
|
||||
ASSERT(textureVk != nullptr);
|
||||
|
||||
const vk::SamplerHelper &samplerVk =
|
||||
sampler ? vk::GetImpl(sampler)->getSampler() : textureVk->getSampler();
|
||||
const SamplerVk *samplerVk = sampler ? vk::GetImpl(sampler) : nullptr;
|
||||
|
||||
if (samplerVk != nullptr && samplerVk->skipSamplerSRGBDecode())
|
||||
{
|
||||
// TODO (http://anglebug.com/5176) Refactor to use ensureImageInitialized instead of
|
||||
// syncState
|
||||
// A sampler may force a texture to reallocate in order to support sRGB_decode
|
||||
// state
|
||||
gl::Texture::DirtyBits decodeBit;
|
||||
decodeBit.set(gl::Texture::DIRTY_BIT_SRGB_DECODE);
|
||||
ANGLE_TRY(textureVk->syncState(context, decodeBit, gl::Command::Other));
|
||||
}
|
||||
|
||||
const vk::SamplerHelper &samplerHelper =
|
||||
samplerVk ? samplerVk->getSampler() : textureVk->getSampler();
|
||||
activeTexture.texture = textureVk;
|
||||
activeTexture.sampler = &samplerVk;
|
||||
activeTexture.sampler = &samplerHelper;
|
||||
activeTexture.useLinearImageView =
|
||||
textureVk->shouldUseLinearColorspaceWithSampler(samplerVk);
|
||||
|
||||
vk::ImageViewSubresourceSerial imageViewSerial = textureVk->getImageViewSubresourceSerial();
|
||||
mActiveTexturesDesc.update(textureUnit, imageViewSerial, samplerVk.getSamplerSerial());
|
||||
mActiveTexturesDesc.update(textureUnit, imageViewSerial, samplerHelper.getSamplerSerial());
|
||||
|
||||
if (textureVk->getImage().hasImmutableSampler())
|
||||
{
|
||||
|
|
|
@ -334,6 +334,8 @@ class ContextVk : public ContextImpl, public vk::Context
|
|||
angle::Result memoryBarrier(const gl::Context *context, GLbitfield barriers) override;
|
||||
angle::Result memoryBarrierByRegion(const gl::Context *context, GLbitfield barriers) override;
|
||||
|
||||
ANGLE_INLINE void invalidateTexture(gl::TextureType target) override {}
|
||||
|
||||
VkDevice getDevice() const;
|
||||
egl::ContextPriority getPriority() const { return mContextPriority; }
|
||||
|
||||
|
|
|
@ -1420,13 +1420,17 @@ angle::Result ProgramExecutableVk::updateTexturesDescriptorSet(ContextVk *contex
|
|||
VkWriteDescriptorSet *writeInfos = contextVk->allocWriteDescriptorSets(arraySize);
|
||||
for (uint32_t arrayElement = 0; arrayElement < arraySize; ++arrayElement)
|
||||
{
|
||||
GLuint textureUnit = samplerBinding.boundTextureUnits[arrayElement];
|
||||
TextureVk *textureVk = activeTextures[textureUnit].texture;
|
||||
const vk::SamplerHelper &samplerVk = *activeTextures[textureUnit].sampler;
|
||||
GLuint textureUnit = samplerBinding.boundTextureUnits[arrayElement];
|
||||
TextureVk *textureVk = activeTextures[textureUnit].texture;
|
||||
const vk::SamplerHelper &samplerHelper = *activeTextures[textureUnit].sampler;
|
||||
bool linearColorspaceWithSampler = activeTextures[textureUnit].useLinearImageView;
|
||||
|
||||
vk::ImageHelper &image = textureVk->getImage();
|
||||
|
||||
imageInfos[arrayElement].sampler = samplerVk.get().getHandle();
|
||||
bool shouldUseLinearColorspace = textureVk->shouldUseLinearColorspaceWithTexelFetch(
|
||||
linearColorspaceWithSampler, samplerUniform.texelFetchInvoked);
|
||||
|
||||
imageInfos[arrayElement].sampler = samplerHelper.get().getHandle();
|
||||
imageInfos[arrayElement].imageLayout = image.getCurrentLayout();
|
||||
|
||||
if (emulateSeamfulCubeMapSampling)
|
||||
|
@ -1434,13 +1438,15 @@ angle::Result ProgramExecutableVk::updateTexturesDescriptorSet(ContextVk *contex
|
|||
// If emulating seamful cubemapping, use the fetch image view. This is
|
||||
// basically the same image view as read, except it's a 2DArray view for
|
||||
// cube maps.
|
||||
imageInfos[arrayElement].imageView =
|
||||
textureVk->getFetchImageViewAndRecordUse(contextVk).getHandle();
|
||||
const vk::ImageView &imageView = textureVk->getFetchImageViewAndRecordUse(
|
||||
contextVk, shouldUseLinearColorspace);
|
||||
imageInfos[arrayElement].imageView = imageView.getHandle();
|
||||
}
|
||||
else
|
||||
{
|
||||
imageInfos[arrayElement].imageView =
|
||||
textureVk->getReadImageViewAndRecordUse(contextVk).getHandle();
|
||||
const vk::ImageView &imageView = textureVk->getReadImageViewAndRecordUse(
|
||||
contextVk, shouldUseLinearColorspace);
|
||||
imageInfos[arrayElement].imageView = imageView.getHandle();
|
||||
}
|
||||
|
||||
if (textureVk->getImage().hasImmutableSampler())
|
||||
|
|
|
@ -2159,23 +2159,26 @@ Serial RendererVk::issueShaderSerial()
|
|||
// These functions look at the mandatory format for support, and fallback to querying the device (if
|
||||
// necessary) to test the availability of the bits.
|
||||
bool RendererVk::hasLinearImageFormatFeatureBits(VkFormat format,
|
||||
const VkFormatFeatureFlags featureBits)
|
||||
const VkFormatFeatureFlags featureBits) const
|
||||
{
|
||||
return hasFormatFeatureBits<&VkFormatProperties::linearTilingFeatures>(format, featureBits);
|
||||
}
|
||||
|
||||
VkFormatFeatureFlags RendererVk::getImageFormatFeatureBits(VkFormat format,
|
||||
const VkFormatFeatureFlags featureBits)
|
||||
VkFormatFeatureFlags RendererVk::getImageFormatFeatureBits(
|
||||
VkFormat format,
|
||||
const VkFormatFeatureFlags featureBits) const
|
||||
{
|
||||
return getFormatFeatureBits<&VkFormatProperties::optimalTilingFeatures>(format, featureBits);
|
||||
}
|
||||
|
||||
bool RendererVk::hasImageFormatFeatureBits(VkFormat format, const VkFormatFeatureFlags featureBits)
|
||||
bool RendererVk::hasImageFormatFeatureBits(VkFormat format,
|
||||
const VkFormatFeatureFlags featureBits) const
|
||||
{
|
||||
return hasFormatFeatureBits<&VkFormatProperties::optimalTilingFeatures>(format, featureBits);
|
||||
}
|
||||
|
||||
bool RendererVk::hasBufferFormatFeatureBits(VkFormat format, const VkFormatFeatureFlags featureBits)
|
||||
bool RendererVk::hasBufferFormatFeatureBits(VkFormat format,
|
||||
const VkFormatFeatureFlags featureBits) const
|
||||
{
|
||||
return hasFormatFeatureBits<&VkFormatProperties::bufferFeatures>(format, featureBits);
|
||||
}
|
||||
|
@ -2328,7 +2331,7 @@ angle::Result RendererVk::newSharedFence(vk::Context *context,
|
|||
|
||||
template <VkFormatFeatureFlags VkFormatProperties::*features>
|
||||
VkFormatFeatureFlags RendererVk::getFormatFeatureBits(VkFormat format,
|
||||
const VkFormatFeatureFlags featureBits)
|
||||
const VkFormatFeatureFlags featureBits) const
|
||||
{
|
||||
ASSERT(static_cast<uint32_t>(format) < vk::kNumVkFormats);
|
||||
VkFormatProperties &deviceProperties = mFormatProperties[format];
|
||||
|
@ -2357,7 +2360,7 @@ VkFormatFeatureFlags RendererVk::getFormatFeatureBits(VkFormat format,
|
|||
}
|
||||
|
||||
template <VkFormatFeatureFlags VkFormatProperties::*features>
|
||||
bool RendererVk::hasFormatFeatureBits(VkFormat format, const VkFormatFeatureFlags featureBits)
|
||||
bool RendererVk::hasFormatFeatureBits(VkFormat format, const VkFormatFeatureFlags featureBits) const
|
||||
{
|
||||
return IsMaskFlagSet(getFormatFeatureBits<features>(format, featureBits), featureBits);
|
||||
}
|
||||
|
|
|
@ -156,11 +156,12 @@ class RendererVk : angle::NonCopyable
|
|||
// Query the format properties for select bits (linearTilingFeatures, optimalTilingFeatures and
|
||||
// bufferFeatures). Looks through mandatory features first, and falls back to querying the
|
||||
// device (first time only).
|
||||
bool hasLinearImageFormatFeatureBits(VkFormat format, const VkFormatFeatureFlags featureBits);
|
||||
bool hasLinearImageFormatFeatureBits(VkFormat format,
|
||||
const VkFormatFeatureFlags featureBits) const;
|
||||
VkFormatFeatureFlags getImageFormatFeatureBits(VkFormat format,
|
||||
const VkFormatFeatureFlags featureBits);
|
||||
bool hasImageFormatFeatureBits(VkFormat format, const VkFormatFeatureFlags featureBits);
|
||||
bool hasBufferFormatFeatureBits(VkFormat format, const VkFormatFeatureFlags featureBits);
|
||||
const VkFormatFeatureFlags featureBits) const;
|
||||
bool hasImageFormatFeatureBits(VkFormat format, const VkFormatFeatureFlags featureBits) const;
|
||||
bool hasBufferFormatFeatureBits(VkFormat format, const VkFormatFeatureFlags featureBits) const;
|
||||
|
||||
ANGLE_INLINE egl::ContextPriority getDriverPriority(egl::ContextPriority priority)
|
||||
{
|
||||
|
@ -289,10 +290,10 @@ class RendererVk : angle::NonCopyable
|
|||
|
||||
template <VkFormatFeatureFlags VkFormatProperties::*features>
|
||||
VkFormatFeatureFlags getFormatFeatureBits(VkFormat format,
|
||||
const VkFormatFeatureFlags featureBits);
|
||||
const VkFormatFeatureFlags featureBits) const;
|
||||
|
||||
template <VkFormatFeatureFlags VkFormatProperties::*features>
|
||||
bool hasFormatFeatureBits(VkFormat format, const VkFormatFeatureFlags featureBits);
|
||||
bool hasFormatFeatureBits(VkFormat format, const VkFormatFeatureFlags featureBits) const;
|
||||
|
||||
angle::Result cleanupGarbage(bool block);
|
||||
|
||||
|
@ -366,7 +367,7 @@ class RendererVk : angle::NonCopyable
|
|||
bool mPipelineCacheInitialized;
|
||||
|
||||
// A cache of VkFormatProperties as queried from the device over time.
|
||||
std::array<VkFormatProperties, vk::kNumVkFormats> mFormatProperties;
|
||||
mutable std::array<VkFormatProperties, vk::kNumVkFormats> mFormatProperties;
|
||||
|
||||
// Latest validation data for debug overlay.
|
||||
std::string mLastValidationMessage;
|
||||
|
|
|
@ -32,6 +32,8 @@ class SamplerVk : public SamplerImpl
|
|||
return mSampler.get();
|
||||
}
|
||||
|
||||
bool skipSamplerSRGBDecode() const { return mState.getSRGBDecode() == GL_SKIP_DECODE_EXT; }
|
||||
|
||||
private:
|
||||
vk::SamplerBinding mSampler;
|
||||
};
|
||||
|
|
|
@ -1157,7 +1157,8 @@ angle::Result TextureVk::setEGLImageTarget(const gl::Context *context,
|
|||
gl::LevelIndex(mState.getEffectiveBaseLevel()), false);
|
||||
|
||||
ASSERT(type != gl::TextureType::CubeMap);
|
||||
ANGLE_TRY(initImageViews(contextVk, format, image->getFormat().info->sized, 1, 1));
|
||||
ANGLE_TRY(initImageViews(contextVk, imageVk->getImage()->getFormat(),
|
||||
image->getFormat().info->sized, 1, 1));
|
||||
|
||||
// Transfer the image to this queue if needed
|
||||
uint32_t rendererQueueFamilyIndex = renderer->getQueueFamilyIndex();
|
||||
|
@ -2106,13 +2107,15 @@ angle::Result TextureVk::syncState(const gl::Context *context,
|
|||
mImageUsageFlags |= VK_IMAGE_USAGE_STORAGE_BIT;
|
||||
}
|
||||
|
||||
if (dirtyBits.test(gl::Texture::DIRTY_BIT_SRGB_OVERRIDE))
|
||||
// If we're handling dirty srgb decode/override state, we may have to reallocate the image with
|
||||
// VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT. Vulkan requires this bit to be set in order to use
|
||||
// imageviews with a format that does not match the texture's internal format.
|
||||
if (dirtyBits.test(gl::Texture::DIRTY_BIT_SRGB_DECODE) ||
|
||||
(dirtyBits.test(gl::Texture::DIRTY_BIT_SRGB_OVERRIDE) &&
|
||||
mState.getSRGBOverride() != gl::SrgbOverride::Default))
|
||||
{
|
||||
if (mState.getSRGBOverride() != gl::SrgbOverride::Default)
|
||||
{
|
||||
mImageCreateFlags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
|
||||
mRequiresSRGBViews = true;
|
||||
}
|
||||
mRequiresSRGBViews = true;
|
||||
mImageCreateFlags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
|
||||
}
|
||||
|
||||
// Before redefining the image for any reason, check to see if it's about to go through mipmap
|
||||
|
@ -2195,7 +2198,8 @@ angle::Result TextureVk::syncState(const gl::Context *context,
|
|||
localBits.test(gl::Texture::DIRTY_BIT_SWIZZLE_GREEN) ||
|
||||
localBits.test(gl::Texture::DIRTY_BIT_SWIZZLE_BLUE) ||
|
||||
localBits.test(gl::Texture::DIRTY_BIT_SWIZZLE_ALPHA) ||
|
||||
localBits.test(gl::Texture::DIRTY_BIT_SRGB_OVERRIDE))
|
||||
localBits.test(gl::Texture::DIRTY_BIT_SRGB_OVERRIDE) ||
|
||||
localBits.test(gl::Texture::DIRTY_BIT_SRGB_DECODE))
|
||||
{
|
||||
// We use a special layer count here to handle EGLImages. They might only be
|
||||
// looking at one layer of a cube or 2D array texture.
|
||||
|
@ -2241,7 +2245,110 @@ void TextureVk::releaseOwnershipOfImage(const gl::Context *context)
|
|||
releaseAndDeleteImage(contextVk);
|
||||
}
|
||||
|
||||
const vk::ImageView &TextureVk::getReadImageViewAndRecordUse(ContextVk *contextVk) const
|
||||
// TODO (http://anglebug.com/5176) Refactor to frontend
|
||||
bool TextureVk::shouldUseLinearColorspaceWithSampler(const SamplerVk *samplerVk) const
|
||||
{
|
||||
ASSERT(mImage->valid());
|
||||
|
||||
// True if GL_TEXTURE_SRGB_DECODE_EXT == GL_SKIP_DECODE_EXT in the texture state
|
||||
bool textureSRGBDecodeDisabled =
|
||||
(mState.getSamplerState().getSRGBDecode() == GL_SKIP_DECODE_EXT);
|
||||
|
||||
// True if GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT == GL_SRGB in the texture state
|
||||
bool textureSRGBOverriddenToNonLinear =
|
||||
(mState.getSRGBOverride() == gl::SrgbOverride::NonLinear);
|
||||
|
||||
gl::SrgbOverride samplerDecodeOverride = gl::SrgbOverride::Default;
|
||||
if (samplerVk != nullptr)
|
||||
{
|
||||
samplerDecodeOverride = (samplerVk->skipSamplerSRGBDecode() ? gl::SrgbOverride::Linear
|
||||
: gl::SrgbOverride::NonLinear);
|
||||
}
|
||||
|
||||
switch (samplerDecodeOverride)
|
||||
{
|
||||
case gl::SrgbOverride::Linear:
|
||||
// If the sampler state skips decoding, we must choose the linear imageview,
|
||||
// regardless of the texture state. This takes precedence over sRGB_override
|
||||
return true;
|
||||
case gl::SrgbOverride::NonLinear:
|
||||
// If the sampler state does not skip decoding, we should choose the imageview
|
||||
// required by sRGB_override- we should not force a linear format to use a nonlinear
|
||||
// imageview if sRGB_override has not forced that
|
||||
if (textureSRGBOverriddenToNonLinear)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(mImage->getFormat().actualImageFormat().isSRGB() ==
|
||||
(vk::ConvertToLinear(mImage->getFormat().vkImageFormat) !=
|
||||
VK_FORMAT_UNDEFINED));
|
||||
return !mImage->getFormat().actualImageFormat().isSRGB();
|
||||
}
|
||||
default:
|
||||
// sRGB_decode texture state takes precedence over sRGB_override texture state
|
||||
if (textureSRGBDecodeDisabled)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (textureSRGBOverriddenToNonLinear)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(mImage->getFormat().actualImageFormat().isSRGB() ==
|
||||
(vk::ConvertToLinear(mImage->getFormat().vkImageFormat) !=
|
||||
VK_FORMAT_UNDEFINED));
|
||||
return !mImage->getFormat().actualImageFormat().isSRGB();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO (http://anglebug.com/5176) Refactor to frontend
|
||||
bool TextureVk::shouldUseLinearColorspaceWithTexelFetch(bool colorspaceWithSampler,
|
||||
bool texelFetchForcesDecodeOn) const
|
||||
{
|
||||
ASSERT(mImage->valid());
|
||||
|
||||
// True if GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT == GL_SRGB in the texture state
|
||||
bool textureSRGBOverriddenToNonLinear =
|
||||
(mState.getSRGBOverride() == gl::SrgbOverride::NonLinear);
|
||||
|
||||
// Enable sRGB decoding regardless of skipSamplerSRGBDecode, due to an edge
|
||||
// case in the EXT_texture_sRGB_decode spec:
|
||||
//
|
||||
// "The conversion of sRGB color space components to linear color space is
|
||||
// always applied if the TEXTURE_SRGB_DECODE_EXT parameter is DECODE_EXT.
|
||||
// Table X.1 describes whether the conversion is skipped if the
|
||||
// TEXTURE_SRGB_DECODE_EXT parameter is SKIP_DECODE_EXT, depending on
|
||||
// the function used for the access, whether the access occurs through a
|
||||
// bindless sampler, and whether the texture is statically accessed
|
||||
// elsewhere with a texelFetch function."
|
||||
if (texelFetchForcesDecodeOn)
|
||||
{
|
||||
// This imageview is used with a texelFetch invocation, so we must ignore all sRGB_decode
|
||||
// state. sRGB_override state should still be considered.
|
||||
if (textureSRGBOverriddenToNonLinear)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(mImage->getFormat().actualImageFormat().isSRGB() ==
|
||||
(vk::ConvertToLinear(mImage->getFormat().vkImageFormat) != VK_FORMAT_UNDEFINED));
|
||||
return !mImage->getFormat().actualImageFormat().isSRGB();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return colorspaceWithSampler;
|
||||
}
|
||||
}
|
||||
|
||||
const vk::ImageView &TextureVk::getReadImageViewAndRecordUse(ContextVk *contextVk,
|
||||
bool useLinearColorspace) const
|
||||
{
|
||||
ASSERT(mImage->valid());
|
||||
|
||||
|
@ -2253,16 +2360,20 @@ const vk::ImageView &TextureVk::getReadImageViewAndRecordUse(ContextVk *contextV
|
|||
return imageViews.getStencilReadImageView();
|
||||
}
|
||||
|
||||
if (mState.getSRGBOverride() == gl::SrgbOverride::Enabled)
|
||||
if (useLinearColorspace)
|
||||
{
|
||||
ASSERT(imageViews.getLinearReadImageView().valid());
|
||||
return imageViews.getLinearReadImageView();
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(imageViews.getNonLinearReadImageView().valid());
|
||||
return imageViews.getNonLinearReadImageView();
|
||||
}
|
||||
|
||||
return imageViews.getReadImageView();
|
||||
}
|
||||
|
||||
const vk::ImageView &TextureVk::getFetchImageViewAndRecordUse(ContextVk *contextVk) const
|
||||
const vk::ImageView &TextureVk::getFetchImageViewAndRecordUse(ContextVk *contextVk,
|
||||
bool useLinearColorspace) const
|
||||
{
|
||||
ASSERT(mImage->valid());
|
||||
|
||||
|
@ -2272,14 +2383,16 @@ const vk::ImageView &TextureVk::getFetchImageViewAndRecordUse(ContextVk *context
|
|||
// We don't currently support fetch for depth/stencil cube map textures.
|
||||
ASSERT(!imageViews.hasStencilReadImageView() || !imageViews.hasFetchImageView());
|
||||
|
||||
if (mState.getSRGBOverride() == gl::SrgbOverride::Enabled)
|
||||
if (useLinearColorspace)
|
||||
{
|
||||
return (imageViews.hasFetchImageView() ? imageViews.getLinearFetchImageView()
|
||||
: imageViews.getLinearReadImageView());
|
||||
}
|
||||
else
|
||||
{
|
||||
return (imageViews.hasFetchImageView() ? imageViews.getNonLinearFetchImageView()
|
||||
: imageViews.getNonLinearReadImageView());
|
||||
}
|
||||
|
||||
return (imageViews.hasFetchImageView() ? imageViews.getFetchImageView()
|
||||
: imageViews.getReadImageView());
|
||||
}
|
||||
|
||||
const vk::ImageView &TextureVk::getCopyImageViewAndRecordUse(ContextVk *contextVk) const
|
||||
|
@ -2289,12 +2402,16 @@ const vk::ImageView &TextureVk::getCopyImageViewAndRecordUse(ContextVk *contextV
|
|||
const vk::ImageViewHelper &imageViews = getImageViews();
|
||||
imageViews.retain(&contextVk->getResourceUseList());
|
||||
|
||||
if (mState.getSRGBOverride() == gl::SrgbOverride::Enabled)
|
||||
ASSERT(mImage->getFormat().actualImageFormat().isSRGB() ==
|
||||
(vk::ConvertToLinear(mImage->getFormat().vkImageFormat) != VK_FORMAT_UNDEFINED));
|
||||
if (!mImage->getFormat().actualImageFormat().isSRGB())
|
||||
{
|
||||
return imageViews.getLinearCopyImageView();
|
||||
}
|
||||
else
|
||||
{
|
||||
return imageViews.getNonLinearCopyImageView();
|
||||
}
|
||||
|
||||
return imageViews.getCopyImageView();
|
||||
}
|
||||
|
||||
angle::Result TextureVk::getLevelLayerImageView(ContextVk *contextVk,
|
||||
|
|
|
@ -174,10 +174,14 @@ class TextureVk : public TextureImpl, public angle::ObserverInterface
|
|||
|
||||
void releaseOwnershipOfImage(const gl::Context *context);
|
||||
|
||||
const vk::ImageView &getReadImageViewAndRecordUse(ContextVk *contextVk) const;
|
||||
const vk::ImageView &getReadImageViewAndRecordUse(ContextVk *contextVk,
|
||||
bool useLinearColorspace) const;
|
||||
|
||||
// A special view for cube maps as a 2D array, used with shaders that do texelFetch() and for
|
||||
// seamful cube map emulation.
|
||||
const vk::ImageView &getFetchImageViewAndRecordUse(ContextVk *contextVk) const;
|
||||
const vk::ImageView &getFetchImageViewAndRecordUse(ContextVk *contextVk,
|
||||
bool useLinearColorspace) const;
|
||||
|
||||
// A special view used for texture copies that shouldn't perform swizzle.
|
||||
const vk::ImageView &getCopyImageViewAndRecordUse(ContextVk *contextVk) const;
|
||||
angle::Result getStorageImageView(ContextVk *contextVk,
|
||||
|
@ -214,6 +218,12 @@ class TextureVk : public TextureImpl, public angle::ObserverInterface
|
|||
|
||||
ANGLE_INLINE bool hasBeenBoundAsImage() const { return mState.hasBeenBoundAsImage(); }
|
||||
|
||||
ANGLE_INLINE bool hasSRGBViews() const { return mRequiresSRGBViews; }
|
||||
|
||||
bool shouldUseLinearColorspaceWithSampler(const SamplerVk *samplerVk) const;
|
||||
bool shouldUseLinearColorspaceWithTexelFetch(bool colorspaceWithSampler,
|
||||
bool texelFetchForcesDecodeOn) const;
|
||||
|
||||
private:
|
||||
// Transform an image index from the frontend into one that can be used on the backing
|
||||
// ImageHelper, taking into account mipmap or cube face offsets
|
||||
|
|
|
@ -27,6 +27,66 @@ constexpr unsigned int kComponentsPerVector = 4;
|
|||
namespace rx
|
||||
{
|
||||
|
||||
namespace vk
|
||||
{
|
||||
namespace
|
||||
{
|
||||
bool FormatReinterpretationSupported(const std::vector<GLenum> &optionalSizedFormats,
|
||||
const RendererVk *rendererVk,
|
||||
bool checkLinearColorspace)
|
||||
{
|
||||
for (GLenum glFormat : optionalSizedFormats)
|
||||
{
|
||||
const gl::TextureCaps &baseCaps = rendererVk->getNativeTextureCaps().get(glFormat);
|
||||
if (baseCaps.texturable && baseCaps.filterable)
|
||||
{
|
||||
const vk::Format &vkFormat = rendererVk->getFormat(glFormat);
|
||||
|
||||
VkFormat reinterpretedFormat = checkLinearColorspace
|
||||
? vk::ConvertToLinear(vkFormat.vkImageFormat)
|
||||
: vk::ConvertToNonLinear(vkFormat.vkImageFormat);
|
||||
ASSERT(reinterpretedFormat != VK_FORMAT_UNDEFINED);
|
||||
|
||||
constexpr uint32_t kBitsSampleFilter =
|
||||
VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT |
|
||||
VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT;
|
||||
|
||||
if (!rendererVk->hasImageFormatFeatureBits(reinterpretedFormat, kBitsSampleFilter))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetTextureSRGBDecodeSupport(const RendererVk *rendererVk)
|
||||
{
|
||||
static constexpr bool kLinearColorspace = true;
|
||||
|
||||
// GL_SRGB and GL_SRGB_ALPHA unsized formats are also required by the spec, but the only valid
|
||||
// type for them is GL_UNSIGNED_BYTE, so they are fully included in the sized formats listed
|
||||
// here
|
||||
std::vector<GLenum> optionalSizedNonLinearFormats = {
|
||||
GL_SRGB8,
|
||||
GL_SRGB8_ALPHA8_EXT,
|
||||
GL_COMPRESSED_SRGB_S3TC_DXT1_EXT,
|
||||
GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,
|
||||
GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT,
|
||||
GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT,
|
||||
};
|
||||
|
||||
if (!FormatReinterpretationSupported(optionalSizedNonLinearFormats, rendererVk,
|
||||
kLinearColorspace))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace
|
||||
} // namespace vk
|
||||
|
||||
GLint LimitToInt(const uint32_t physicalDeviceValue)
|
||||
{
|
||||
// Limit to INT_MAX / 2 instead of INT_MAX. If the limit is queried as float, the imprecision
|
||||
|
@ -48,14 +108,6 @@ void RendererVk::ensureCapsInitialized() const
|
|||
|
||||
mNativeExtensions.setTextureExtensionSupport(mNativeTextureCaps);
|
||||
|
||||
// Enable GL_EXT_buffer_storage"
|
||||
mNativeExtensions.bufferStorageEXT = true;
|
||||
|
||||
// TODO: http://anglebug.com/3609
|
||||
// Due to a dEQP bug, this extension cannot be exposed until EXT_texture_sRGB_decode is
|
||||
// implemented
|
||||
mNativeExtensions.sRGBR8EXT = false;
|
||||
|
||||
// To ensure that ETC2/EAC formats are enabled only on hardware that supports them natively,
|
||||
// this flag is not set by the function above and must be set explicitly. It exposes
|
||||
// ANGLE_compressed_texture_etc extension string.
|
||||
|
@ -200,8 +252,10 @@ void RendererVk::ensureCapsInitialized() const
|
|||
mNativeExtensions.depthTextureCubeMapOES =
|
||||
mNativeExtensions.depthTextureOES && mNativeExtensions.packedDepthStencilOES;
|
||||
|
||||
// Vulkan natively supports format reinterpretation
|
||||
mNativeExtensions.textureSRGBOverride = mNativeExtensions.sRGB;
|
||||
// Vulkan natively supports format reinterpretation, but we still require support for all
|
||||
// formats we may reinterpret to
|
||||
mNativeExtensions.textureSRGBOverride = true;
|
||||
mNativeExtensions.textureSRGBDecode = vk::GetTextureSRGBDecodeSupport(this);
|
||||
|
||||
mNativeExtensions.gpuShader5EXT = vk::CanSupportGPUShader5EXT(mPhysicalDeviceFeatures);
|
||||
|
||||
|
|
|
@ -6020,8 +6020,18 @@ angle::Result ImageViewHelper::initSRGBReadViewsImpl(ContextVk *contextVk,
|
|||
uint32_t layerCount,
|
||||
VkImageUsageFlags imageUsageFlags)
|
||||
{
|
||||
// When we select the linear/nonlinear counterpart formats, we must first make sure they're
|
||||
// actually supported by the ICD. If they are not supported by the ICD, then we treat that as if
|
||||
// there is no counterpart format. (In this case, the relevant extension should not be exposed)
|
||||
VkFormat nonLinearOverrideFormat = ConvertToNonLinear(image.getFormat().vkImageFormat);
|
||||
VkFormat linearOverrideFormat = ConvertToLinear(image.getFormat().vkImageFormat);
|
||||
ASSERT(
|
||||
(nonLinearOverrideFormat == VK_FORMAT_UNDEFINED) ||
|
||||
(HasNonRenderableTextureFormatSupport(contextVk->getRenderer(), nonLinearOverrideFormat)));
|
||||
|
||||
VkFormat linearOverrideFormat = ConvertToLinear(image.getFormat().vkImageFormat);
|
||||
ASSERT((linearOverrideFormat == VK_FORMAT_UNDEFINED) ||
|
||||
(HasNonRenderableTextureFormatSupport(contextVk->getRenderer(), linearOverrideFormat)));
|
||||
|
||||
VkFormat linearFormat =
|
||||
(linearOverrideFormat != VK_FORMAT_UNDEFINED) ? linearOverrideFormat : format.vkImageFormat;
|
||||
ASSERT(linearFormat != VK_FORMAT_UNDEFINED);
|
||||
|
|
|
@ -44,6 +44,7 @@ struct TextureUnit final
|
|||
{
|
||||
TextureVk *texture;
|
||||
const SamplerHelper *sampler;
|
||||
bool useLinearImageView;
|
||||
};
|
||||
|
||||
// A dynamic buffer is conceptually an infinitely long buffer. Each time you write to the buffer,
|
||||
|
|
|
@ -747,6 +747,80 @@ TEST_P(ProgramBinaryES3Test, BinaryWithLargeUniformCount)
|
|||
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::magenta);
|
||||
}
|
||||
|
||||
// Test that sampler texelFetch references are saved and loaded correctly
|
||||
TEST_P(ProgramBinaryTest, SRGBDecodeWithSamplerAndTexelFetchTest)
|
||||
{
|
||||
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_sRGB_decode") ||
|
||||
getClientMajorVersion() < 3);
|
||||
|
||||
// These OpenGL drivers appear not to respect the texelFetch exception
|
||||
// http://anglebug.com/4991
|
||||
ANGLE_SKIP_TEST_IF(IsOpenGL() && IsIntel() && IsWindows());
|
||||
ANGLE_SKIP_TEST_IF(IsOpenGL() && IsAMD() && IsWindows());
|
||||
ANGLE_SKIP_TEST_IF(IsOpenGL() && IsNVIDIA() && IsOSX());
|
||||
ANGLE_SKIP_TEST_IF(IsOpenGLES() && IsNexus5X());
|
||||
|
||||
constexpr char kVS[] =
|
||||
"#version 300 es\n"
|
||||
"precision highp float;\n"
|
||||
"in vec4 position;\n"
|
||||
"\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" gl_Position = vec4(position.xy, 0.0, 1.0);\n"
|
||||
"}\n";
|
||||
|
||||
constexpr char kFS[] =
|
||||
"#version 300 es\n"
|
||||
"precision highp float;\n"
|
||||
"uniform sampler2D tex;\n"
|
||||
"in vec2 texcoord;\n"
|
||||
"out vec4 out_color;\n"
|
||||
"\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" out_color = texelFetch(tex, ivec2(0, 0), 0);\n"
|
||||
"}\n";
|
||||
|
||||
GLProgram program;
|
||||
program.makeRaster(kVS, kFS);
|
||||
ASSERT_NE(0u, program.get());
|
||||
|
||||
GLuint reloadedProgram = glCreateProgram();
|
||||
saveAndLoadProgram(program.get(), reloadedProgram);
|
||||
|
||||
GLint textureLocation = glGetUniformLocation(reloadedProgram, "tex");
|
||||
ASSERT_NE(-1, textureLocation);
|
||||
|
||||
GLColor linearColor(64, 127, 191, 255);
|
||||
GLColor srgbColor(13, 54, 133, 255);
|
||||
|
||||
GLTexture tex;
|
||||
glBindTexture(GL_TEXTURE_2D, tex.get());
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB8_ALPHA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
&linearColor);
|
||||
ASSERT_GL_NO_ERROR();
|
||||
|
||||
GLSampler sampler;
|
||||
glBindSampler(0, sampler.get());
|
||||
glSamplerParameteri(sampler.get(), GL_TEXTURE_SRGB_DECODE_EXT, GL_DECODE_EXT);
|
||||
|
||||
glUseProgram(reloadedProgram);
|
||||
glUniform1i(textureLocation, 0);
|
||||
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
drawQuad(reloadedProgram, "position", 0.5f);
|
||||
|
||||
EXPECT_PIXEL_COLOR_NEAR(0, 0, srgbColor, 1.0);
|
||||
|
||||
glSamplerParameteri(sampler.get(), GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT);
|
||||
drawQuad(reloadedProgram, "position", 0.5f);
|
||||
|
||||
EXPECT_PIXEL_COLOR_NEAR(0, 0, srgbColor, 1.0);
|
||||
|
||||
glDeleteProgram(reloadedProgram);
|
||||
}
|
||||
|
||||
ANGLE_INSTANTIATE_TEST_ES3(ProgramBinaryES3Test);
|
||||
|
||||
class ProgramBinaryES31Test : public ANGLETest
|
||||
|
|
|
@ -304,6 +304,46 @@ TEST_P(SRGBTextureTest, SRGBOverrideTextureParameter)
|
|||
EXPECT_PIXEL_COLOR_NEAR(0, 0, srgbColor, 1.0);
|
||||
}
|
||||
|
||||
// Test interaction between sRGB_override and sampler objects
|
||||
TEST_P(SRGBTextureTest, SRGBOverrideTextureParameterWithSampler)
|
||||
{
|
||||
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_sRGB_override") ||
|
||||
getClientMajorVersion() < 3);
|
||||
|
||||
GLColor linearColor = kLinearColor;
|
||||
GLColor srgbColor = kNonlinearColor;
|
||||
|
||||
GLenum internalFormat = getClientMajorVersion() >= 3 ? GL_RGBA8 : GL_RGBA;
|
||||
|
||||
GLTexture tex;
|
||||
glBindTexture(GL_TEXTURE_2D, tex.get());
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
&linearColor);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT, GL_NONE);
|
||||
ASSERT_GL_NO_ERROR();
|
||||
|
||||
GLSampler sampler;
|
||||
glBindSampler(0, sampler.get());
|
||||
|
||||
glUseProgram(mProgram);
|
||||
glUniform1i(mTextureLocation, 0);
|
||||
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
drawQuad(mProgram, "position", 0.5f);
|
||||
|
||||
EXPECT_PIXEL_COLOR_NEAR(0, 0, linearColor, 1.0);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT, GL_SRGB);
|
||||
drawQuad(mProgram, "position", 0.5f);
|
||||
|
||||
EXPECT_PIXEL_COLOR_NEAR(0, 0, srgbColor, 1.0);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT, GL_NONE);
|
||||
drawQuad(mProgram, "position", 0.5f);
|
||||
|
||||
EXPECT_PIXEL_COLOR_NEAR(0, 0, linearColor, 1.0);
|
||||
}
|
||||
|
||||
// Test that SRGB override is a noop when used on a nonlinear texture format
|
||||
// EXT_texture_format_sRGB_override spec says:
|
||||
// "If the internal format is not one of the above formats, then
|
||||
|
@ -370,6 +410,72 @@ TEST_P(SRGBTextureTest, SRGBDecodeSamplerParameter)
|
|||
EXPECT_PIXEL_COLOR_NEAR(0, 0, linearColor, 1.0);
|
||||
}
|
||||
|
||||
// Test that sampler state overrides texture state for srgb decode
|
||||
TEST_P(SRGBTextureTest, SRGBDecodeTextureAndSamplerParameter)
|
||||
{
|
||||
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_sRGB_decode") ||
|
||||
getClientMajorVersion() < 3);
|
||||
|
||||
GLColor linearColor = kLinearColor;
|
||||
GLColor srgbColor = kNonlinearColor;
|
||||
|
||||
GLTexture tex;
|
||||
glBindTexture(GL_TEXTURE_2D, tex.get());
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, getSRGBA8TextureInternalFormat(), 1, 1, 0,
|
||||
getSRGBA8TextureFormat(), GL_UNSIGNED_BYTE, &linearColor);
|
||||
|
||||
ASSERT_GL_NO_ERROR();
|
||||
|
||||
GLSampler sampler;
|
||||
glBindSampler(0, sampler.get());
|
||||
|
||||
glUseProgram(mProgram);
|
||||
glUniform1i(mTextureLocation, 0);
|
||||
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT);
|
||||
glSamplerParameteri(sampler.get(), GL_TEXTURE_SRGB_DECODE_EXT, GL_DECODE_EXT);
|
||||
drawQuad(mProgram, "position", 0.5f);
|
||||
|
||||
EXPECT_PIXEL_COLOR_NEAR(0, 0, srgbColor, 1.0);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SRGB_DECODE_EXT, GL_DECODE_EXT);
|
||||
glSamplerParameteri(sampler.get(), GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT);
|
||||
drawQuad(mProgram, "position", 0.5f);
|
||||
|
||||
EXPECT_PIXEL_COLOR_NEAR(0, 0, linearColor, 1.0);
|
||||
}
|
||||
|
||||
// Test that srgb decode state takes priority over srgb override state
|
||||
TEST_P(SRGBTextureTest, SRGBDecodeOverridePriority)
|
||||
{
|
||||
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_sRGB_decode") ||
|
||||
getClientMajorVersion() < 3);
|
||||
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_sRGB_override"));
|
||||
|
||||
GLColor linearColor = kLinearColor;
|
||||
|
||||
GLenum internalFormat = getClientMajorVersion() >= 3 ? GL_RGBA8 : GL_RGBA;
|
||||
|
||||
GLTexture tex;
|
||||
glBindTexture(GL_TEXTURE_2D, tex.get());
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
&linearColor);
|
||||
ASSERT_GL_NO_ERROR();
|
||||
|
||||
glUseProgram(mProgram);
|
||||
glUniform1i(mTextureLocation, 0);
|
||||
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT, GL_SRGB);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT);
|
||||
drawQuad(mProgram, "position", 0.5f);
|
||||
|
||||
EXPECT_PIXEL_COLOR_NEAR(0, 0, linearColor, 1.0);
|
||||
}
|
||||
|
||||
// Test that mipmaps are generated correctly for sRGB textures
|
||||
TEST_P(SRGBTextureTest, GenerateMipmaps)
|
||||
{
|
||||
|
|
Загрузка…
Ссылка в новой задаче