Commit 33e30205 by Jamie Madill Committed by Commit Bot

Vulkan: sRGB cleanups.

A few fixes to how we check for the sRGB override in the TextureVk class. In at least one instance there was a potential edge case where in syncState we might not create the Texture with the mutable bit the second time through the function. Bug: angleproject:5176 Change-Id: I4f1ca6e469b10514c3a0de3120be9ade62568084 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2482292Reviewed-by: 's avatarMohan Maiya <m.maiya@samsung.com> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent a7c16c2d
...@@ -4167,23 +4167,20 @@ angle::Result ContextVk::updateActiveTextures(const gl::Context *context) ...@@ -4167,23 +4167,20 @@ angle::Result ContextVk::updateActiveTextures(const gl::Context *context)
const SamplerVk *samplerVk = sampler ? vk::GetImpl(sampler) : nullptr; 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 = const vk::SamplerHelper &samplerHelper =
samplerVk ? samplerVk->getSampler() : textureVk->getSampler(); samplerVk ? samplerVk->getSampler() : textureVk->getSampler();
activeTexture.texture = textureVk; const gl::SamplerState &samplerState =
activeTexture.sampler = &samplerHelper; sampler ? sampler->getSamplerState() : texture->getSamplerState();
activeTexture.useLinearImageView = activeTexture.texture = textureVk;
textureVk->shouldUseLinearColorspaceWithSampler(samplerVk); activeTexture.sampler = &samplerHelper;
activeTexture.srgbDecode = samplerState.getSRGBDecode();
if (activeTexture.srgbDecode == GL_SKIP_DECODE_EXT)
{
// Make sure we use the MUTABLE bit for the storage. Because the "skip decode" is a
// Sampler state we might not have caught this setting in TextureVk::syncState.
ANGLE_TRY(textureVk->ensureMutable(this));
}
vk::ImageViewSubresourceSerial imageViewSerial = textureVk->getImageViewSubresourceSerial(); vk::ImageViewSubresourceSerial imageViewSerial = textureVk->getImageViewSubresourceSerial();
mActiveTexturesDesc.update(textureUnit, imageViewSerial, samplerHelper.getSamplerSerial()); mActiveTexturesDesc.update(textureUnit, imageViewSerial, samplerHelper.getSamplerSerial());
......
...@@ -1455,16 +1455,13 @@ angle::Result ProgramExecutableVk::updateTexturesDescriptorSet(ContextVk *contex ...@@ -1455,16 +1455,13 @@ angle::Result ProgramExecutableVk::updateTexturesDescriptorSet(ContextVk *contex
VkWriteDescriptorSet *writeInfos = contextVk->allocWriteDescriptorSets(arraySize); VkWriteDescriptorSet *writeInfos = contextVk->allocWriteDescriptorSets(arraySize);
for (uint32_t arrayElement = 0; arrayElement < arraySize; ++arrayElement) for (uint32_t arrayElement = 0; arrayElement < arraySize; ++arrayElement)
{ {
GLuint textureUnit = samplerBinding.boundTextureUnits[arrayElement]; GLuint textureUnit = samplerBinding.boundTextureUnits[arrayElement];
TextureVk *textureVk = activeTextures[textureUnit].texture; const vk::TextureUnit &unit = activeTextures[textureUnit];
const vk::SamplerHelper &samplerHelper = *activeTextures[textureUnit].sampler; TextureVk *textureVk = unit.texture;
bool linearColorspaceWithSampler = activeTextures[textureUnit].useLinearImageView; const vk::SamplerHelper &samplerHelper = *unit.sampler;
vk::ImageHelper &image = textureVk->getImage(); vk::ImageHelper &image = textureVk->getImage();
bool shouldUseLinearColorspace = textureVk->shouldUseLinearColorspaceWithTexelFetch(
linearColorspaceWithSampler, samplerUniform.texelFetchStaticUse);
imageInfos[arrayElement].sampler = samplerHelper.get().getHandle(); imageInfos[arrayElement].sampler = samplerHelper.get().getHandle();
imageInfos[arrayElement].imageLayout = image.getCurrentLayout(); imageInfos[arrayElement].imageLayout = image.getCurrentLayout();
...@@ -1474,13 +1471,13 @@ angle::Result ProgramExecutableVk::updateTexturesDescriptorSet(ContextVk *contex ...@@ -1474,13 +1471,13 @@ angle::Result ProgramExecutableVk::updateTexturesDescriptorSet(ContextVk *contex
// basically the same image view as read, except it's a 2DArray view for // basically the same image view as read, except it's a 2DArray view for
// cube maps. // cube maps.
const vk::ImageView &imageView = textureVk->getFetchImageViewAndRecordUse( const vk::ImageView &imageView = textureVk->getFetchImageViewAndRecordUse(
contextVk, shouldUseLinearColorspace); contextVk, unit.srgbDecode, samplerUniform.texelFetchStaticUse);
imageInfos[arrayElement].imageView = imageView.getHandle(); imageInfos[arrayElement].imageView = imageView.getHandle();
} }
else else
{ {
const vk::ImageView &imageView = textureVk->getReadImageViewAndRecordUse( const vk::ImageView &imageView = textureVk->getReadImageViewAndRecordUse(
contextVk, shouldUseLinearColorspace); contextVk, unit.srgbDecode, samplerUniform.texelFetchStaticUse);
imageInfos[arrayElement].imageView = imageView.getHandle(); imageInfos[arrayElement].imageView = imageView.getHandle();
} }
......
...@@ -32,8 +32,6 @@ class SamplerVk : public SamplerImpl ...@@ -32,8 +32,6 @@ class SamplerVk : public SamplerImpl
return mSampler.get(); return mSampler.get();
} }
bool skipSamplerSRGBDecode() const { return mState.getSRGBDecode() == GL_SKIP_DECODE_EXT; }
private: private:
vk::SamplerBinding mSampler; vk::SamplerBinding mSampler;
}; };
......
...@@ -143,8 +143,7 @@ bool CanGenerateMipmapWithCompute(RendererVk *renderer, ...@@ -143,8 +143,7 @@ bool CanGenerateMipmapWithCompute(RendererVk *renderer,
format.vkImageFormat, VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT); format.vkImageFormat, VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT);
// No support for sRGB formats yet. // No support for sRGB formats yet.
const bool isSRGB = const bool isSRGB = angleFormat.isSRGB;
gl::GetSizedInternalFormatInfo(format.internalFormat).colorEncoding == GL_SRGB;
// No support for integer formats yet. // No support for integer formats yet.
const bool isInt = angleFormat.isInt(); const bool isInt = angleFormat.isInt();
...@@ -209,7 +208,7 @@ void Set3DBaseArrayLayerAndLayerCount(VkImageSubresourceLayers *Subresource) ...@@ -209,7 +208,7 @@ void Set3DBaseArrayLayerAndLayerCount(VkImageSubresourceLayers *Subresource)
TextureVk::TextureVk(const gl::TextureState &state, RendererVk *renderer) TextureVk::TextureVk(const gl::TextureState &state, RendererVk *renderer)
: TextureImpl(state), : TextureImpl(state),
mOwnsImage(false), mOwnsImage(false),
mRequiresSRGBViews(false), mRequiresMutableStorage(false),
mImageNativeType(gl::TextureType::InvalidEnum), mImageNativeType(gl::TextureType::InvalidEnum),
mImageLayerOffset(0), mImageLayerOffset(0),
mImageLevelOffset(0), mImageLevelOffset(0),
...@@ -1156,9 +1155,10 @@ angle::Result TextureVk::setEGLImageTarget(const gl::Context *context, ...@@ -1156,9 +1155,10 @@ angle::Result TextureVk::setEGLImageTarget(const gl::Context *context,
imageVk->getImageLevel().get(), imageVk->getImageLayer(), imageVk->getImageLevel().get(), imageVk->getImageLayer(),
gl::LevelIndex(mState.getEffectiveBaseLevel()), false); gl::LevelIndex(mState.getEffectiveBaseLevel()), false);
initImageUsageFlags(contextVk, format);
ASSERT(type != gl::TextureType::CubeMap); ASSERT(type != gl::TextureType::CubeMap);
ANGLE_TRY(initImageViews(contextVk, imageVk->getImage()->getFormat(), ANGLE_TRY(initImageViews(contextVk, format, image->getFormat().info->sized, 1, 1));
image->getFormat().info->sized, 1, 1));
// Transfer the image to this queue if needed // Transfer the image to this queue if needed
uint32_t rendererQueueFamilyIndex = renderer->getQueueFamilyIndex(); uint32_t rendererQueueFamilyIndex = renderer->getQueueFamilyIndex();
...@@ -1239,23 +1239,8 @@ void TextureVk::releaseAndDeleteImage(ContextVk *contextVk) ...@@ -1239,23 +1239,8 @@ void TextureVk::releaseAndDeleteImage(ContextVk *contextVk)
mRedefinedLevels.reset(); mRedefinedLevels.reset();
} }
angle::Result TextureVk::ensureImageAllocated(ContextVk *contextVk, const vk::Format &format) void TextureVk::initImageUsageFlags(ContextVk *contextVk, const vk::Format &format)
{ {
if (mImage == nullptr)
{
setImageHelper(contextVk, new vk::ImageHelper(), mState.getType(), format, 0, 0,
gl::LevelIndex(0), true);
}
else
{
// Note: one possible path here is when an image level is being redefined to a different
// format. In that case, staged updates with the new format should succeed, but otherwise
// the format should not affect the currently allocated image. The following function only
// takes the alignment requirement to make sure the format is not accidentally used for any
// other purpose.
updateImageHelper(contextVk, format.getImageCopyBufferAlignment());
}
mImageUsageFlags = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | mImageUsageFlags = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
VK_IMAGE_USAGE_SAMPLED_BIT; VK_IMAGE_USAGE_SAMPLED_BIT;
...@@ -1277,6 +1262,26 @@ angle::Result TextureVk::ensureImageAllocated(ContextVk *contextVk, const vk::Fo ...@@ -1277,6 +1262,26 @@ angle::Result TextureVk::ensureImageAllocated(ContextVk *contextVk, const vk::Fo
mImageUsageFlags |= mImageUsageFlags |=
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
} }
}
angle::Result TextureVk::ensureImageAllocated(ContextVk *contextVk, const vk::Format &format)
{
if (mImage == nullptr)
{
setImageHelper(contextVk, new vk::ImageHelper(), mState.getType(), format, 0, 0,
gl::LevelIndex(0), true);
}
else
{
// Note: one possible path here is when an image level is being redefined to a different
// format. In that case, staged updates with the new format should succeed, but otherwise
// the format should not affect the currently allocated image. The following function only
// takes the alignment requirement to make sure the format is not accidentally used for any
// other purpose.
updateImageHelper(contextVk, format.getImageCopyBufferAlignment());
}
initImageUsageFlags(contextVk, format);
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -1510,8 +1515,7 @@ angle::Result TextureVk::generateMipmapsWithCompute(ContextVk *contextVk) ...@@ -1510,8 +1515,7 @@ angle::Result TextureVk::generateMipmapsWithCompute(ContextVk *contextVk)
// //
// Support for the first two can be added easily. Supporting 3D textures, MSAA and // Support for the first two can be added easily. Supporting 3D textures, MSAA and
// depth/stencil would be more involved. // depth/stencil would be more involved.
ASSERT(gl::GetSizedInternalFormatInfo(mImage->getFormat().internalFormat).colorEncoding != ASSERT(!mImage->getFormat().actualImageFormat().isSRGB);
GL_SRGB);
ASSERT(!mImage->getFormat().actualImageFormat().isInt()); ASSERT(!mImage->getFormat().actualImageFormat().isInt());
ASSERT(mImage->getType() == VK_IMAGE_TYPE_2D); ASSERT(mImage->getType() == VK_IMAGE_TYPE_2D);
ASSERT(mImage->getSamples() == 1); ASSERT(mImage->getSamples() == 1);
...@@ -1779,20 +1783,20 @@ angle::Result TextureVk::updateBaseMaxLevels(ContextVk *contextVk, ...@@ -1779,20 +1783,20 @@ angle::Result TextureVk::updateBaseMaxLevels(ContextVk *contextVk,
maxLevel - baseLevel + 1, layerCount); maxLevel - baseLevel + 1, layerCount);
} }
return respecifyImageAttributesAndLevels(contextVk, previousBaseLevel, baseLevel, maxLevel); return respecifyImageStorageAndLevels(contextVk, previousBaseLevel, baseLevel, maxLevel);
} }
angle::Result TextureVk::respecifyImageAttributes(ContextVk *contextVk) angle::Result TextureVk::respecifyImageStorage(ContextVk *contextVk)
{ {
return respecifyImageAttributesAndLevels(contextVk, mImage->getBaseLevel(), return respecifyImageStorageAndLevels(contextVk, mImage->getBaseLevel(),
gl::LevelIndex(mState.getEffectiveBaseLevel()), gl::LevelIndex(mState.getEffectiveBaseLevel()),
gl::LevelIndex(mState.getEffectiveMaxLevel())); gl::LevelIndex(mState.getEffectiveMaxLevel()));
} }
angle::Result TextureVk::respecifyImageAttributesAndLevels(ContextVk *contextVk, angle::Result TextureVk::respecifyImageStorageAndLevels(ContextVk *contextVk,
gl::LevelIndex previousBaseLevel, gl::LevelIndex previousBaseLevel,
gl::LevelIndex baseLevel, gl::LevelIndex baseLevel,
gl::LevelIndex maxLevel) gl::LevelIndex maxLevel)
{ {
// Recreate the image to reflect new base or max levels. // Recreate the image to reflect new base or max levels.
// First, flush any pending updates so we have good data in the existing vkImage // First, flush any pending updates so we have good data in the existing vkImage
...@@ -2101,20 +2105,22 @@ angle::Result TextureVk::syncState(const gl::Context *context, ...@@ -2101,20 +2105,22 @@ angle::Result TextureVk::syncState(const gl::Context *context,
VkImageCreateFlags oldCreateFlags = mImageCreateFlags; VkImageCreateFlags oldCreateFlags = mImageCreateFlags;
// Create a new image if the storage state is enabled for the first time. // Create a new image if the storage state is enabled for the first time.
if (dirtyBits.test(gl::Texture::DIRTY_BIT_BOUND_AS_IMAGE)) if (mState.hasBeenBoundAsImage())
{ {
mImageCreateFlags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
mImageUsageFlags |= VK_IMAGE_USAGE_STORAGE_BIT; mImageUsageFlags |= VK_IMAGE_USAGE_STORAGE_BIT;
mRequiresMutableStorage = true;
} }
// If we're handling dirty srgb decode/override state, we may have to reallocate the image with // 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 // 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. // imageviews with a format that does not match the texture's internal format.
if (dirtyBits.test(gl::Texture::DIRTY_BIT_SRGB_DECODE) || if (isSRGBOverrideEnabled())
(dirtyBits.test(gl::Texture::DIRTY_BIT_SRGB_OVERRIDE) && {
mState.getSRGBOverride() != gl::SrgbOverride::Default)) mRequiresMutableStorage = true;
}
if (mRequiresMutableStorage)
{ {
mRequiresSRGBViews = true;
mImageCreateFlags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; mImageCreateFlags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
} }
...@@ -2171,7 +2177,7 @@ angle::Result TextureVk::syncState(const gl::Context *context, ...@@ -2171,7 +2177,7 @@ angle::Result TextureVk::syncState(const gl::Context *context,
if (oldUsageFlags != mImageUsageFlags || oldCreateFlags != mImageCreateFlags || if (oldUsageFlags != mImageUsageFlags || oldCreateFlags != mImageCreateFlags ||
mRedefinedLevels.any() || isMipmapEnabledByMinFilter) mRedefinedLevels.any() || isMipmapEnabledByMinFilter)
{ {
ANGLE_TRY(respecifyImageAttributes(contextVk)); ANGLE_TRY(respecifyImageStorage(contextVk));
} }
// Initialize the image storage and flush the pixel buffer. // Initialize the image storage and flush the pixel buffer.
...@@ -2201,19 +2207,7 @@ angle::Result TextureVk::syncState(const gl::Context *context, ...@@ -2201,19 +2207,7 @@ angle::Result TextureVk::syncState(const gl::Context *context,
localBits.test(gl::Texture::DIRTY_BIT_SRGB_OVERRIDE) || localBits.test(gl::Texture::DIRTY_BIT_SRGB_OVERRIDE) ||
localBits.test(gl::Texture::DIRTY_BIT_SRGB_DECODE)) localBits.test(gl::Texture::DIRTY_BIT_SRGB_DECODE))
{ {
// We use a special layer count here to handle EGLImages. They might only be ANGLE_TRY(refreshImageViews(contextVk));
// looking at one layer of a cube or 2D array texture.
uint32_t layerCount =
mState.getType() == gl::TextureType::_2D ? 1 : mImage->getLayerCount();
getImageViews().release(renderer);
const gl::ImageDesc &baseLevelDesc = mState.getBaseLevelDesc();
ANGLE_TRY(initImageViews(contextVk, mImage->getFormat(), baseLevelDesc.format.info->sized,
mImage->getLevelCount(), layerCount));
// Let any Framebuffers know we need to refresh the RenderTarget cache.
onStateChange(angle::SubjectMessage::SubjectChanged);
} }
vk::SamplerDesc samplerDesc(contextVk->getFeatures(), mState.getSamplerState(), vk::SamplerDesc samplerDesc(contextVk->getFeatures(), mState.getSamplerState(),
...@@ -2245,108 +2239,38 @@ void TextureVk::releaseOwnershipOfImage(const gl::Context *context) ...@@ -2245,108 +2239,38 @@ void TextureVk::releaseOwnershipOfImage(const gl::Context *context)
releaseAndDeleteImage(contextVk); releaseAndDeleteImage(contextVk);
} }
// TODO (http://anglebug.com/5176) Refactor to frontend bool TextureVk::shouldDecodeSRGB(ContextVk *contextVk,
bool TextureVk::shouldUseLinearColorspaceWithSampler(const SamplerVk *samplerVk) const GLenum srgbDecode,
bool texelFetchStaticUse) const
{ {
ASSERT(mImage->valid()); // By default, we decode SRGB images.
const vk::Format &format = getBaseLevelFormat(contextVk->getRenderer());
bool decodeSRGB = format.actualImageFormat().isSRGB;
// True if GL_TEXTURE_SRGB_DECODE_EXT == GL_SKIP_DECODE_EXT in the texture state // If the SRGB override is enabled, we also decode SRGB.
bool textureSRGBDecodeDisabled = if (isSRGBOverrideEnabled() && vk::IsOverridableLinearFormat(format.vkImageFormat))
(mState.getSamplerState().getSRGBDecode() == GL_SKIP_DECODE_EXT);
// True if GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT == GL_SRGB in the texture state
bool textureSRGBOverriddenToSRGB = (mState.getSRGBOverride() == gl::SrgbOverride::SRGB);
gl::SrgbOverride samplerDecodeOverride = gl::SrgbOverride::Default;
if (samplerVk != nullptr)
{
samplerDecodeOverride = (samplerVk->skipSamplerSRGBDecode() ? gl::SrgbOverride::Linear
: gl::SrgbOverride::SRGB);
}
switch (samplerDecodeOverride)
{ {
case gl::SrgbOverride::Linear: decodeSRGB = true;
// 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::SRGB:
// 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 SRGB
// imageview if sRGB_override has not forced that
if (textureSRGBOverriddenToSRGB)
{
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 (textureSRGBOverriddenToSRGB)
{
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 // The decode step is optionally disabled by the skip decode setting, except for texelFetch:
bool textureSRGBOverriddenToSRGB = (mState.getSRGBOverride() == gl::SrgbOverride::SRGB);
// 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 // "The conversion of sRGB color space components to linear color space is always applied if the
// always applied if the TEXTURE_SRGB_DECODE_EXT parameter is DECODE_EXT. // TEXTURE_SRGB_DECODE_EXT parameter is DECODE_EXT. Table X.1 describes whether the conversion
// Table X.1 describes whether the conversion is skipped if the // is skipped if the TEXTURE_SRGB_DECODE_EXT parameter is SKIP_DECODE_EXT, depending on the
// TEXTURE_SRGB_DECODE_EXT parameter is SKIP_DECODE_EXT, depending on // function used for the access, whether the access occurs through a bindless sampler, and
// the function used for the access, whether the access occurs through a // whether the texture is statically accessed elsewhere with a texelFetch function."
// bindless sampler, and whether the texture is statically accessed if (srgbDecode == GL_SKIP_DECODE_EXT && !texelFetchStaticUse)
// 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 (textureSRGBOverriddenToSRGB)
{
return false;
}
else
{
ASSERT(mImage->getFormat().actualImageFormat().isSRGB ==
(vk::ConvertToLinear(mImage->getFormat().vkImageFormat) != VK_FORMAT_UNDEFINED));
return !mImage->getFormat().actualImageFormat().isSRGB;
}
}
else
{ {
return colorspaceWithSampler; decodeSRGB = false;
} }
return decodeSRGB;
} }
const vk::ImageView &TextureVk::getReadImageViewAndRecordUse(ContextVk *contextVk, const vk::ImageView &TextureVk::getReadImageViewAndRecordUse(ContextVk *contextVk,
bool useLinearColorspace) const GLenum srgbDecode,
bool texelFetchStaticUse) const
{ {
ASSERT(mImage->valid()); ASSERT(mImage->valid());
...@@ -2358,20 +2282,19 @@ const vk::ImageView &TextureVk::getReadImageViewAndRecordUse(ContextVk *contextV ...@@ -2358,20 +2282,19 @@ const vk::ImageView &TextureVk::getReadImageViewAndRecordUse(ContextVk *contextV
return imageViews.getStencilReadImageView(); return imageViews.getStencilReadImageView();
} }
if (useLinearColorspace) if (shouldDecodeSRGB(contextVk, srgbDecode, texelFetchStaticUse))
{
ASSERT(imageViews.getLinearReadImageView().valid());
return imageViews.getLinearReadImageView();
}
else
{ {
ASSERT(imageViews.getSRGBReadImageView().valid()); ASSERT(imageViews.getSRGBReadImageView().valid());
return imageViews.getSRGBReadImageView(); return imageViews.getSRGBReadImageView();
} }
ASSERT(imageViews.getLinearReadImageView().valid());
return imageViews.getLinearReadImageView();
} }
const vk::ImageView &TextureVk::getFetchImageViewAndRecordUse(ContextVk *contextVk, const vk::ImageView &TextureVk::getFetchImageViewAndRecordUse(ContextVk *contextVk,
bool useLinearColorspace) const GLenum srgbDecode,
bool texelFetchStaticUse) const
{ {
ASSERT(mImage->valid()); ASSERT(mImage->valid());
...@@ -2381,16 +2304,14 @@ const vk::ImageView &TextureVk::getFetchImageViewAndRecordUse(ContextVk *context ...@@ -2381,16 +2304,14 @@ const vk::ImageView &TextureVk::getFetchImageViewAndRecordUse(ContextVk *context
// We don't currently support fetch for depth/stencil cube map textures. // We don't currently support fetch for depth/stencil cube map textures.
ASSERT(!imageViews.hasStencilReadImageView() || !imageViews.hasFetchImageView()); ASSERT(!imageViews.hasStencilReadImageView() || !imageViews.hasFetchImageView());
if (useLinearColorspace) if (shouldDecodeSRGB(contextVk, srgbDecode, texelFetchStaticUse))
{
return (imageViews.hasFetchImageView() ? imageViews.getLinearFetchImageView()
: imageViews.getLinearReadImageView());
}
else
{ {
return (imageViews.hasFetchImageView() ? imageViews.getSRGBFetchImageView() return (imageViews.hasFetchImageView() ? imageViews.getSRGBFetchImageView()
: imageViews.getSRGBReadImageView()); : imageViews.getSRGBReadImageView());
} }
return (imageViews.hasFetchImageView() ? imageViews.getLinearFetchImageView()
: imageViews.getLinearReadImageView());
} }
const vk::ImageView &TextureVk::getCopyImageViewAndRecordUse(ContextVk *contextVk) const const vk::ImageView &TextureVk::getCopyImageViewAndRecordUse(ContextVk *contextVk) const
...@@ -2402,14 +2323,11 @@ const vk::ImageView &TextureVk::getCopyImageViewAndRecordUse(ContextVk *contextV ...@@ -2402,14 +2323,11 @@ const vk::ImageView &TextureVk::getCopyImageViewAndRecordUse(ContextVk *contextV
ASSERT(mImage->getFormat().actualImageFormat().isSRGB == ASSERT(mImage->getFormat().actualImageFormat().isSRGB ==
(vk::ConvertToLinear(mImage->getFormat().vkImageFormat) != VK_FORMAT_UNDEFINED)); (vk::ConvertToLinear(mImage->getFormat().vkImageFormat) != VK_FORMAT_UNDEFINED));
if (!mImage->getFormat().actualImageFormat().isSRGB) if (mImage->getFormat().actualImageFormat().isSRGB)
{
return imageViews.getLinearCopyImageView();
}
else
{ {
return imageViews.getSRGBCopyImageView(); return imageViews.getSRGBCopyImageView();
} }
return imageViews.getLinearCopyImageView();
} }
angle::Result TextureVk::getLevelLayerImageView(ContextVk *contextVk, angle::Result TextureVk::getLevelLayerImageView(ContextVk *contextVk,
...@@ -2493,9 +2411,12 @@ angle::Result TextureVk::initImageViews(ContextVk *contextVk, ...@@ -2493,9 +2411,12 @@ angle::Result TextureVk::initImageViews(ContextVk *contextVk,
gl::SwizzleState formatSwizzle = GetFormatSwizzle(contextVk, format, sized); gl::SwizzleState formatSwizzle = GetFormatSwizzle(contextVk, format, sized);
gl::SwizzleState readSwizzle = ApplySwizzle(formatSwizzle, mState.getSwizzleState()); gl::SwizzleState readSwizzle = ApplySwizzle(formatSwizzle, mState.getSwizzleState());
// Use this as a proxy for the SRGB override & skip decode settings.
bool createExtraSRGBViews = mRequiresMutableStorage;
ANGLE_TRY(getImageViews().initReadViews(contextVk, mState.getType(), *mImage, format, ANGLE_TRY(getImageViews().initReadViews(contextVk, mState.getType(), *mImage, format,
formatSwizzle, readSwizzle, baseLevelVk, levelCount, formatSwizzle, readSwizzle, baseLevelVk, levelCount,
baseLayer, layerCount, mRequiresSRGBViews, baseLayer, layerCount, createExtraSRGBViews,
mImageUsageFlags & ~VK_IMAGE_USAGE_STORAGE_BIT)); mImageUsageFlags & ~VK_IMAGE_USAGE_STORAGE_BIT));
return angle::Result::Continue; return angle::Result::Continue;
...@@ -2712,4 +2633,38 @@ vk::ImageViewSubresourceSerial TextureVk::getImageViewSubresourceSerial() const ...@@ -2712,4 +2633,38 @@ vk::ImageViewSubresourceSerial TextureVk::getImageViewSubresourceSerial() const
uint32_t levelCount = gl::LevelIndex(mState.getMipmapMaxLevel()) - baseLevel + 1; uint32_t levelCount = gl::LevelIndex(mState.getMipmapMaxLevel()) - baseLevel + 1;
return getImageViews().getSubresourceSerial(baseLevel, levelCount, 0, vk::LayerMode::All); return getImageViews().getSubresourceSerial(baseLevel, levelCount, 0, vk::LayerMode::All);
} }
angle::Result TextureVk::refreshImageViews(ContextVk *contextVk)
{
// 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.
uint32_t layerCount = mState.getType() == gl::TextureType::_2D ? 1 : mImage->getLayerCount();
getImageViews().release(contextVk->getRenderer());
const gl::ImageDesc &baseLevelDesc = mState.getBaseLevelDesc();
ANGLE_TRY(initImageViews(contextVk, mImage->getFormat(), baseLevelDesc.format.info->sized,
mImage->getLevelCount(), layerCount));
// Let any Framebuffers know we need to refresh the RenderTarget cache.
onStateChange(angle::SubjectMessage::SubjectChanged);
return angle::Result::Continue;
}
angle::Result TextureVk::ensureMutable(ContextVk *contextVk)
{
if (mRequiresMutableStorage)
{
return angle::Result::Continue;
}
mRequiresMutableStorage = true;
mImageCreateFlags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
ANGLE_TRY(respecifyImageStorage(contextVk));
ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
return refreshImageViews(contextVk);
}
} // namespace rx } // namespace rx
...@@ -175,12 +175,14 @@ class TextureVk : public TextureImpl, public angle::ObserverInterface ...@@ -175,12 +175,14 @@ class TextureVk : public TextureImpl, public angle::ObserverInterface
void releaseOwnershipOfImage(const gl::Context *context); void releaseOwnershipOfImage(const gl::Context *context);
const vk::ImageView &getReadImageViewAndRecordUse(ContextVk *contextVk, const vk::ImageView &getReadImageViewAndRecordUse(ContextVk *contextVk,
bool useLinearColorspace) const; GLenum srgbDecode,
bool texelFetchStaticUse) const;
// A special view for cube maps as a 2D array, used with shaders that do texelFetch() and for // A special view for cube maps as a 2D array, used with shaders that do texelFetch() and for
// seamful cube map emulation. // seamful cube map emulation.
const vk::ImageView &getFetchImageViewAndRecordUse(ContextVk *contextVk, const vk::ImageView &getFetchImageViewAndRecordUse(ContextVk *contextVk,
bool useLinearColorspace) const; GLenum srgbDecode,
bool texelFetchStaticUse) const;
// A special view used for texture copies that shouldn't perform swizzle. // A special view used for texture copies that shouldn't perform swizzle.
const vk::ImageView &getCopyImageViewAndRecordUse(ContextVk *contextVk) const; const vk::ImageView &getCopyImageViewAndRecordUse(ContextVk *contextVk) const;
...@@ -218,11 +220,12 @@ class TextureVk : public TextureImpl, public angle::ObserverInterface ...@@ -218,11 +220,12 @@ class TextureVk : public TextureImpl, public angle::ObserverInterface
ANGLE_INLINE bool hasBeenBoundAsImage() const { return mState.hasBeenBoundAsImage(); } ANGLE_INLINE bool hasBeenBoundAsImage() const { return mState.hasBeenBoundAsImage(); }
ANGLE_INLINE bool hasSRGBViews() const { return mRequiresSRGBViews; } bool isSRGBOverrideEnabled() const
{
return mState.getSRGBOverride() != gl::SrgbOverride::Default;
}
bool shouldUseLinearColorspaceWithSampler(const SamplerVk *samplerVk) const; angle::Result ensureMutable(ContextVk *contextVk);
bool shouldUseLinearColorspaceWithTexelFetch(bool colorspaceWithSampler,
bool texelFetchForcesDecodeOn) const;
private: private:
// Transform an image index from the frontend into one that can be used on the backing // Transform an image index from the frontend into one that can be used on the backing
...@@ -395,11 +398,11 @@ class TextureVk : public TextureImpl, public angle::ObserverInterface ...@@ -395,11 +398,11 @@ class TextureVk : public TextureImpl, public angle::ObserverInterface
const vk::Format &getBaseLevelFormat(RendererVk *renderer) const; const vk::Format &getBaseLevelFormat(RendererVk *renderer) const;
// Queues a flush of any modified image attributes. The image will be reallocated with its new // Queues a flush of any modified image attributes. The image will be reallocated with its new
// attributes at the next opportunity. // attributes at the next opportunity.
angle::Result respecifyImageAttributes(ContextVk *contextVk); angle::Result respecifyImageStorage(ContextVk *contextVk);
angle::Result respecifyImageAttributesAndLevels(ContextVk *contextVk, angle::Result respecifyImageStorageAndLevels(ContextVk *contextVk,
gl::LevelIndex previousBaseLevelGL, gl::LevelIndex previousBaseLevelGL,
gl::LevelIndex baseLevelGL, gl::LevelIndex baseLevelGL,
gl::LevelIndex maxLevelGL); gl::LevelIndex maxLevelGL);
// Update base and max levels, and re-create image if needed. // Update base and max levels, and re-create image if needed.
angle::Result updateBaseMaxLevels(ContextVk *contextVk, angle::Result updateBaseMaxLevels(ContextVk *contextVk,
...@@ -419,8 +422,12 @@ class TextureVk : public TextureImpl, public angle::ObserverInterface ...@@ -419,8 +422,12 @@ class TextureVk : public TextureImpl, public angle::ObserverInterface
return (mImage->valid()) ? mImage->getTilingMode() : VK_IMAGE_TILING_OPTIMAL; return (mImage->valid()) ? mImage->getTilingMode() : VK_IMAGE_TILING_OPTIMAL;
} }
angle::Result refreshImageViews(ContextVk *contextVk);
bool shouldDecodeSRGB(ContextVk *contextVk, GLenum srgbDecode, bool texelFetchStaticUse) const;
void initImageUsageFlags(ContextVk *contextVk, const vk::Format &format);
bool mOwnsImage; bool mOwnsImage;
bool mRequiresSRGBViews; bool mRequiresMutableStorage;
gl::TextureType mImageNativeType; gl::TextureType mImageNativeType;
......
...@@ -325,19 +325,10 @@ ANGLE_INLINE VkFormat ConvertToLinear(VkFormat format) ...@@ -325,19 +325,10 @@ ANGLE_INLINE VkFormat ConvertToLinear(VkFormat format)
} }
} }
ANGLE_INLINE bool IsSRGBFormat(VkFormat format)
{
return ConvertToLinear(format) != VK_FORMAT_UNDEFINED;
}
ANGLE_INLINE bool IsOverridableLinearFormat(VkFormat format) ANGLE_INLINE bool IsOverridableLinearFormat(VkFormat format)
{ {
return ConvertToSRGB(format) != VK_FORMAT_UNDEFINED; return ConvertToSRGB(format) != VK_FORMAT_UNDEFINED;
} }
ANGLE_INLINE bool IsLinearFormat(VkFormat format)
{
return !IsSRGBFormat(format);
}
} // namespace vk } // namespace vk
} // namespace rx } // namespace rx
......
...@@ -5975,7 +5975,7 @@ angle::Result ImageViewHelper::initReadViewsImpl(ContextVk *contextVk, ...@@ -5975,7 +5975,7 @@ angle::Result ImageViewHelper::initReadViewsImpl(ContextVk *contextVk,
ASSERT(mImageViewSerial.valid()); ASSERT(mImageViewSerial.valid());
const VkImageAspectFlags aspectFlags = GetFormatAspectFlags(format.intendedFormat()); const VkImageAspectFlags aspectFlags = GetFormatAspectFlags(format.intendedFormat());
mLinearColorspace = IsLinearFormat(format.vkImageFormat); mLinearColorspace = !format.actualImageFormat().isSRGB;
if (HasBothDepthAndStencilAspects(aspectFlags)) if (HasBothDepthAndStencilAspects(aspectFlags))
{ {
......
...@@ -44,7 +44,7 @@ struct TextureUnit final ...@@ -44,7 +44,7 @@ struct TextureUnit final
{ {
TextureVk *texture; TextureVk *texture;
const SamplerHelper *sampler; const SamplerHelper *sampler;
bool useLinearImageView; GLenum srgbDecode;
}; };
// A dynamic buffer is conceptually an infinitely long buffer. Each time you write to the buffer, // A dynamic buffer is conceptually an infinitely long buffer. Each time you write to the buffer,
......
...@@ -719,6 +719,10 @@ class ImageTest : public ANGLETest ...@@ -719,6 +719,10 @@ class ImageTest : public ANGLETest
bool hasImageGLColorspaceExt() const bool hasImageGLColorspaceExt() const
{ {
// Vulkan back-end bug: http://anglebug.com/5209
if (IsVulkan())
return false;
return IsEGLDisplayExtensionEnabled(getEGLWindow()->getDisplay(), kImageGLColorspaceExt); return IsEGLDisplayExtensionEnabled(getEGLWindow()->getDisplay(), kImageGLColorspaceExt);
} }
......
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