Commit 8f6d1af9 by Brandon Schade Committed by Commit Bot

Vulkan: Implement EXT_texture_format_sRGB_override

Implemented support for EXT_texture_format_sRGB_override This is done by creating new imageviews for textures with sRGB overridden that reinterpret the format to its sRGB counterpart. As preparation for this, textures that use this feature are reallocated with VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT. This will have a performance cost for textures that use this feature, but should have no performance cost for regular textures, since they will not have this bit set. Bug: angleproject:4561 Test: angle_end2end_tests --gtest_filter=SRGBTextureTest.*Vulkan* Change-Id: Iba25f1f2b0a7227959c1cb4ba6e3ca8311c20d06 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2152145 Commit-Queue: Mohan Maiya <m.maiya@samsung.com> Reviewed-by: 's avatarTim Van Patten <timvp@google.com>
parent d949154d
......@@ -228,6 +228,15 @@ const char *GetDebugMessageSourceString(GLenum source);
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.
enum class SrgbOverride
{
Default = 0,
Enabled
};
} // namespace gl
namespace egl
......
......@@ -982,6 +982,7 @@ const ExtensionInfoMap &GetExtensionInfoMap()
map["GL_CHROMIUM_bind_generates_resource"] = esOnlyExtension(&Extensions::bindGeneratesResource);
map["GL_ANGLE_robust_client_memory"] = esOnlyExtension(&Extensions::robustClientMemory);
map["GL_EXT_texture_sRGB_decode"] = esOnlyExtension(&Extensions::textureSRGBDecode);
map["GL_EXT_texture_sRGB_override"] = esOnlyExtension(&Extensions::textureSRGBOverride);
map["GL_EXT_sRGB_write_control"] = esOnlyExtension(&Extensions::sRGBWriteControl);
map["GL_CHROMIUM_color_buffer_float_rgb"] = enableableExtension(&Extensions::colorBufferFloatRGB);
map["GL_CHROMIUM_color_buffer_float_rgba"] = enableableExtension(&Extensions::colorBufferFloatRGBA);
......
......@@ -492,6 +492,9 @@ struct Extensions
// GL_EXT_texture_sRGB_decode
bool textureSRGBDecode = false;
// GL_EXT_texture_sRGB_override
bool textureSRGBOverride = false;
// GL_EXT_sRGB_write_control
bool sRGBWriteControl = false;
......
......@@ -95,6 +95,7 @@ bool SwizzleState::operator!=(const SwizzleState &other) const
TextureState::TextureState(TextureType type)
: mType(type),
mSamplerState(SamplerState::CreateDefaultForTarget(type)),
mSrgbOverride(SrgbOverride::Default),
mBaseLevel(0),
mMaxLevel(1000),
mDepthStencilTextureMode(GL_DEPTH_COMPONENT),
......@@ -859,6 +860,22 @@ GLenum Texture::getSRGBDecode() const
return mState.mSamplerState.getSRGBDecode();
}
void Texture::setSRGBOverride(const Context *context, GLenum sRGBOverride)
{
SrgbOverride oldOverride = mState.mSrgbOverride;
mState.mSrgbOverride =
(sRGBOverride == GL_SRGB) ? SrgbOverride::Enabled : SrgbOverride::Default;
if (mState.mSrgbOverride != oldOverride)
{
signalDirtyState(DIRTY_BIT_SRGB_OVERRIDE);
}
}
GLenum Texture::getSRGBOverride() const
{
return (mState.mSrgbOverride == SrgbOverride::Enabled) ? GL_SRGB : GL_NONE;
}
const SamplerState &Texture::getSamplerState() const
{
return mState.mSamplerState;
......
......@@ -151,6 +151,8 @@ class TextureState final : private angle::NonCopyable
return getBindingCount(contextID).imageBindingCount > 0;
}
gl::SrgbOverride getSRGBOverride() const { return mSrgbOverride; }
// Returns the desc of the base level. Only valid for cube-complete/mip-complete textures.
const ImageDesc &getBaseLevelDesc() const;
......@@ -216,6 +218,8 @@ class TextureState final : private angle::NonCopyable
SamplerState mSamplerState;
SrgbOverride mSrgbOverride;
GLuint mBaseLevel;
GLuint mMaxLevel;
......@@ -308,6 +312,9 @@ class Texture final : public RefCountObject<TextureID>,
void setSRGBDecode(const Context *context, GLenum sRGBDecode);
GLenum getSRGBDecode() const;
void setSRGBOverride(const Context *context, GLenum sRGBOverride);
GLenum getSRGBOverride() const;
const SamplerState &getSamplerState() const;
angle::Result setBaseLevel(const Context *context, GLuint baseLevel);
......@@ -549,6 +556,7 @@ class Texture final : public RefCountObject<TextureID>,
DIRTY_BIT_COMPARE_MODE,
DIRTY_BIT_COMPARE_FUNC,
DIRTY_BIT_SRGB_DECODE,
DIRTY_BIT_SRGB_OVERRIDE,
DIRTY_BIT_BORDER_COLOR,
// Texture state
......
......@@ -304,6 +304,9 @@ void QueryTexParameterBase(const Context *context,
case GL_TEXTURE_SRGB_DECODE_EXT:
*params = CastFromGLintStateValue<ParamType>(pname, texture->getSRGBDecode());
break;
case GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT:
*params = CastFromGLintStateValue<ParamType>(pname, texture->getSRGBOverride());
break;
case GL_DEPTH_STENCIL_TEXTURE_MODE:
*params =
CastFromGLintStateValue<ParamType>(pname, texture->getDepthStencilTextureMode());
......@@ -432,6 +435,9 @@ void SetTexParameterBase(Context *context, Texture *texture, GLenum pname, const
case GL_TEXTURE_SRGB_DECODE_EXT:
texture->setSRGBDecode(context, ConvertToGLenum(pname, params[0]));
break;
case GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT:
texture->setSRGBOverride(context, ConvertToGLenum(pname, params[0]));
break;
case GL_TEXTURE_CROP_RECT_OES:
texture->setCrop(gl::Rectangle(ConvertTexParam<isGLfixed, GLint>(pname, params[0]),
ConvertTexParam<isGLfixed, GLint>(pname, params[1]),
......
......@@ -196,10 +196,10 @@ angle::Result MemoryObjectVk::createImage(ContextVk *contextVk,
//
// If the content is not already defined, the first operation may not be a
// glWaitSemaphore, but in this case undefined layout is appropriate.
ANGLE_TRY(image->initExternal(contextVk, type, vkExtents, vkFormat, 1, imageUsageFlags,
vk::ImageLayout::Undefined, &externalMemoryImageCreateInfo, 0,
static_cast<uint32_t>(levels) - 1, static_cast<uint32_t>(levels),
layerCount));
ANGLE_TRY(image->initExternal(
contextVk, type, vkExtents, vkFormat, 1, imageUsageFlags, vk::kVkImageCreateFlagsNone,
vk::ImageLayout::Undefined, &externalMemoryImageCreateInfo, 0,
static_cast<uint32_t>(levels) - 1, static_cast<uint32_t>(levels), layerCount));
VkMemoryRequirements externalMemoryRequirements;
image->getImage().getMemoryRequirements(renderer->getDevice(), &externalMemoryRequirements);
......
......@@ -123,6 +123,7 @@ TextureVk::TextureVk(const gl::TextureState &state, RendererVk *renderer)
mImage(nullptr),
mStagingBufferInitialSize(vk::kStagingBufferSize),
mImageUsageFlags(0),
mImageCreateFlags(0),
mImageObserverBinding(this, kTextureImageSubjectIndex)
{}
......@@ -1209,7 +1210,7 @@ angle::Result TextureVk::copyAndStageImageSubresource(ContextVk *contextVk,
&layerCount);
gl::Box area(offset.x, offset.y, offset.z, updatedExtents.width, updatedExtents.height,
updatedExtents.depth);
// TODO: Refactor TextureVk::changeLevels() to avoid this workaround.
// TODO: Refactor TextureVk::respecifyImageAttributesAndLevels() to avoid this workaround.
if (ignoreLayerCount)
{
layerCount = 1;
......@@ -1278,13 +1279,19 @@ angle::Result TextureVk::updateBaseMaxLevels(ContextVk *contextVk,
return angle::Result::Continue;
}
return changeLevels(contextVk, previousBaseLevel, baseLevel, maxLevel);
return respecifyImageAttributesAndLevels(contextVk, previousBaseLevel, baseLevel, maxLevel);
}
angle::Result TextureVk::changeLevels(ContextVk *contextVk,
GLuint previousBaseLevel,
GLuint baseLevel,
GLuint maxLevel)
angle::Result TextureVk::respecifyImageAttributes(ContextVk *contextVk)
{
return respecifyImageAttributesAndLevels(contextVk, mImage->getBaseLevel(),
mState.getEffectiveBaseLevel(),
mState.getEffectiveMaxLevel());
}
angle::Result TextureVk::respecifyImageAttributesAndLevels(ContextVk *contextVk,
GLuint previousBaseLevel,
GLuint baseLevel,
GLuint maxLevel)
{
// Recreate the image to reflect new base or max levels.
// First, flush any pending updates so we have good data in the existing vkImage
......@@ -1320,8 +1327,8 @@ angle::Result TextureVk::changeLevels(ContextVk *contextVk,
// layer/level, we don't need to propagate any data from this image.
// This can happen for original texture levels that have never fit into
// the vkImage due to base/max level, and for vkImage data that has been
// staged by previous calls to changeLevels that didn't fit into the
// new vkImage.
// staged by previous calls to respecifyImageAttributesAndLevels that didn't fit
// into the new vkImage.
continue;
}
......@@ -1475,6 +1482,9 @@ angle::Result TextureVk::syncState(const gl::Context *context,
{
ContextVk *contextVk = vk::GetImpl(context);
VkImageUsageFlags oldUsageFlags = mImageUsageFlags;
VkImageCreateFlags oldCreateFlags = mImageCreateFlags;
// Create a new image if the storage state is enabled for the first time.
if (dirtyBits.test(gl::Texture::DIRTY_BIT_BOUND_AS_IMAGE))
{
......@@ -1482,11 +1492,23 @@ angle::Result TextureVk::syncState(const gl::Context *context,
if (!(mImageUsageFlags & VK_IMAGE_USAGE_STORAGE_BIT))
{
mImageUsageFlags |= VK_IMAGE_USAGE_STORAGE_BIT;
ANGLE_TRY(changeLevels(contextVk, mImage->getBaseLevel(),
mState.getEffectiveBaseLevel(), mState.getEffectiveMaxLevel()));
}
}
if (dirtyBits.test(gl::Texture::DIRTY_BIT_SRGB_OVERRIDE))
{
if (!(mImageCreateFlags & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT) &&
mState.getSRGBOverride() != gl::SrgbOverride::Default)
{
mImageCreateFlags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
}
}
if (oldUsageFlags != mImageUsageFlags || oldCreateFlags != mImageCreateFlags)
{
ANGLE_TRY(respecifyImageAttributes(contextVk));
}
// Set base and max level before initializing the image
if (dirtyBits.test(gl::Texture::DIRTY_BIT_MAX_LEVEL) ||
dirtyBits.test(gl::Texture::DIRTY_BIT_BASE_LEVEL))
......@@ -1516,7 +1538,8 @@ angle::Result TextureVk::syncState(const gl::Context *context,
if (localBits.test(gl::Texture::DIRTY_BIT_SWIZZLE_RED) ||
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_SWIZZLE_ALPHA) ||
localBits.test(gl::Texture::DIRTY_BIT_SRGB_OVERRIDE))
{
if (mImage && mImage->valid())
{
......@@ -1576,6 +1599,12 @@ const vk::ImageView &TextureVk::getReadImageViewAndRecordUse(ContextVk *contextV
return mImageViews.getStencilReadImageView();
}
if (mState.getSRGBOverride() == gl::SrgbOverride::Enabled)
{
ASSERT(mImageViews.getNonLinearReadImageView().valid());
return mImageViews.getNonLinearReadImageView();
}
return mImageViews.getReadImageView();
}
......@@ -1587,6 +1616,13 @@ const vk::ImageView &TextureVk::getFetchImageViewAndRecordUse(ContextVk *context
// We don't currently support fetch for depth/stencil cube map textures.
ASSERT(!mImageViews.hasStencilReadImageView() || !mImageViews.hasFetchImageView());
if (mState.getSRGBOverride() == gl::SrgbOverride::Enabled)
{
return (mImageViews.hasFetchImageView() ? mImageViews.getNonLinearFetchImageView()
: mImageViews.getNonLinearReadImageView());
}
return (mImageViews.hasFetchImageView() ? mImageViews.getFetchImageView()
: mImageViews.getReadImageView());
}
......@@ -1635,9 +1671,10 @@ angle::Result TextureVk::initImage(ContextVk *contextVk,
gl_vk::GetExtentsAndLayerCount(mState.getType(), extents, &vkExtent, &layerCount);
GLint samples = mState.getBaseLevelDesc().samples ? mState.getBaseLevelDesc().samples : 1;
ANGLE_TRY(mImage->init(contextVk, mState.getType(), vkExtent, format, samples, mImageUsageFlags,
mState.getEffectiveBaseLevel(), mState.getEffectiveMaxLevel(),
levelCount, layerCount));
ANGLE_TRY(mImage->initExternal(
contextVk, mState.getType(), vkExtent, format, samples, mImageUsageFlags, mImageCreateFlags,
rx::vk::ImageLayout::Undefined, nullptr, mState.getEffectiveBaseLevel(),
mState.getEffectiveMaxLevel(), levelCount, layerCount));
const VkMemoryPropertyFlags flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
......@@ -1665,8 +1702,17 @@ angle::Result TextureVk::initImageViews(ContextVk *contextVk,
gl::SwizzleState mappedSwizzle;
MapSwizzleState(contextVk, format, sized, mState.getSwizzleState(), &mappedSwizzle);
return mImageViews.initReadViews(contextVk, mState.getType(), *mImage, format, mappedSwizzle,
baseLevel, levelCount, baseLayer, layerCount);
ANGLE_TRY(mImageViews.initReadViews(contextVk, mState.getType(), *mImage, format, mappedSwizzle,
baseLevel, levelCount, baseLayer, layerCount));
if ((mImageCreateFlags & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT) != 0)
{
ANGLE_TRY(mImageViews.initSRGBReadViews(contextVk, mState.getType(), *mImage, format,
mappedSwizzle, baseLevel, levelCount, baseLayer,
layerCount));
}
return angle::Result::Continue;
}
void TextureVk::releaseImage(ContextVk *contextVk)
......
......@@ -376,11 +376,13 @@ class TextureVk : public TextureImpl, public angle::ObserverInterface
const gl::InternalFormat &getImplementationSizedFormat(const gl::Context *context) const;
const vk::Format &getBaseLevelFormat(RendererVk *renderer) const;
// Re-create the image.
angle::Result changeLevels(ContextVk *contextVk,
GLuint previousBaseLevel,
GLuint baseLevel,
GLuint maxLevel);
// Queues a flush of any modified image attributes. The image will be reallocated with its new
// attributes at the next opportunity.
angle::Result respecifyImageAttributes(ContextVk *contextVk);
angle::Result respecifyImageAttributesAndLevels(ContextVk *contextVk,
GLuint previousBaseLevel,
GLuint baseLevel,
GLuint maxLevel);
// Update base and max levels, and re-create image if needed.
angle::Result updateBaseMaxLevels(ContextVk *contextVk, GLuint baseLevel, GLuint maxLevel);
......@@ -428,6 +430,9 @@ class TextureVk : public TextureImpl, public angle::ObserverInterface
// The created vkImage usage flag.
VkImageUsageFlags mImageUsageFlags;
// Additional image create flags
VkImageCreateFlags mImageCreateFlags;
angle::ObserverBinding mImageObserverBinding;
};
......
......@@ -126,9 +126,9 @@ angle::Result HardwareBufferImageSiblingVkAndroid::initImpl(DisplayVk *displayVk
gl_vk::GetExtent(mSize, &vkExtents);
mImage = new vk::ImageHelper();
ANGLE_TRY(mImage->initExternal(displayVk, gl::TextureType::_2D, vkExtents, vkFormat, 1, usage,
vk::ImageLayout::ExternalPreInitialized,
&externalMemoryImageCreateInfo, 0, 0, 1, 1));
ANGLE_TRY(mImage->initExternal(
displayVk, gl::TextureType::_2D, vkExtents, vkFormat, 1, usage, vk::kVkImageCreateFlagsNone,
vk::ImageLayout::ExternalPreInitialized, &externalMemoryImageCreateInfo, 0, 0, 1, 1));
VkImportAndroidHardwareBufferInfoANDROID importHardwareBufferInfo = {};
importHardwareBufferInfo.sType = VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID;
......
......@@ -181,6 +181,9 @@ void RendererVk::ensureCapsInitialized() const
mNativeExtensions.depthTextureCubeMapOES =
mNativeExtensions.depthTextureOES && mNativeExtensions.packedDepthStencilOES;
// Vulkan natively supports format reinterpretation
mNativeExtensions.textureSRGBOverride = mNativeExtensions.sRGB;
mNativeExtensions.gpuShader5EXT = vk::CanSupportGPUShader5EXT(mPhysicalDeviceFeatures);
// https://vulkan.lunarg.com/doc/view/1.0.30.0/linux/vkspec.chunked/ch31s02.html
......
......@@ -168,6 +168,154 @@ void MapSwizzleState(const ContextVk *contextVk,
const bool sized,
const gl::SwizzleState &swizzleState,
gl::SwizzleState *swizzleStateOut);
namespace vk
{
ANGLE_INLINE VkFormat ConvertToNonLinear(VkFormat format)
{
switch (format)
{
case VK_FORMAT_R8_UNORM:
return VK_FORMAT_R8_SRGB;
case VK_FORMAT_R8G8_UNORM:
return VK_FORMAT_R8G8_SRGB;
case VK_FORMAT_R8G8B8_UNORM:
return VK_FORMAT_R8G8B8_SRGB;
case VK_FORMAT_B8G8R8_UNORM:
return VK_FORMAT_B8G8R8_SRGB;
case VK_FORMAT_R8G8B8A8_UNORM:
return VK_FORMAT_R8G8B8A8_SRGB;
case VK_FORMAT_B8G8R8A8_UNORM:
return VK_FORMAT_B8G8R8A8_SRGB;
case VK_FORMAT_BC1_RGB_UNORM_BLOCK:
return VK_FORMAT_BC1_RGB_SRGB_BLOCK;
case VK_FORMAT_BC1_RGBA_UNORM_BLOCK:
return VK_FORMAT_BC1_RGBA_SRGB_BLOCK;
case VK_FORMAT_BC2_UNORM_BLOCK:
return VK_FORMAT_BC2_SRGB_BLOCK;
case VK_FORMAT_BC3_UNORM_BLOCK:
return VK_FORMAT_BC3_SRGB_BLOCK;
case VK_FORMAT_BC7_UNORM_BLOCK:
return VK_FORMAT_BC7_SRGB_BLOCK;
case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
return VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK;
case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
return VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK;
case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
return VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK;
case VK_FORMAT_ASTC_4x4_UNORM_BLOCK:
return VK_FORMAT_ASTC_4x4_SRGB_BLOCK;
case VK_FORMAT_ASTC_5x4_UNORM_BLOCK:
return VK_FORMAT_ASTC_5x4_SRGB_BLOCK;
case VK_FORMAT_ASTC_5x5_UNORM_BLOCK:
return VK_FORMAT_ASTC_5x5_SRGB_BLOCK;
case VK_FORMAT_ASTC_6x5_UNORM_BLOCK:
return VK_FORMAT_ASTC_6x5_SRGB_BLOCK;
case VK_FORMAT_ASTC_6x6_UNORM_BLOCK:
return VK_FORMAT_ASTC_6x6_SRGB_BLOCK;
case VK_FORMAT_ASTC_8x5_UNORM_BLOCK:
return VK_FORMAT_ASTC_8x5_SRGB_BLOCK;
case VK_FORMAT_ASTC_8x6_UNORM_BLOCK:
return VK_FORMAT_ASTC_8x6_SRGB_BLOCK;
case VK_FORMAT_ASTC_8x8_UNORM_BLOCK:
return VK_FORMAT_ASTC_8x8_SRGB_BLOCK;
case VK_FORMAT_ASTC_10x5_UNORM_BLOCK:
return VK_FORMAT_ASTC_10x5_SRGB_BLOCK;
case VK_FORMAT_ASTC_10x6_UNORM_BLOCK:
return VK_FORMAT_ASTC_10x6_SRGB_BLOCK;
case VK_FORMAT_ASTC_10x8_UNORM_BLOCK:
return VK_FORMAT_ASTC_10x8_SRGB_BLOCK;
case VK_FORMAT_ASTC_10x10_UNORM_BLOCK:
return VK_FORMAT_ASTC_10x10_SRGB_BLOCK;
case VK_FORMAT_ASTC_12x10_UNORM_BLOCK:
return VK_FORMAT_ASTC_12x10_SRGB_BLOCK;
case VK_FORMAT_ASTC_12x12_UNORM_BLOCK:
return VK_FORMAT_ASTC_12x12_SRGB_BLOCK;
default:
return VK_FORMAT_UNDEFINED;
}
}
ANGLE_INLINE VkFormat ConvertToLinear(VkFormat format)
{
switch (format)
{
case VK_FORMAT_R8_SRGB:
return VK_FORMAT_R8_UNORM;
case VK_FORMAT_R8G8_SRGB:
return VK_FORMAT_R8G8_UNORM;
case VK_FORMAT_R8G8B8_SRGB:
return VK_FORMAT_R8G8B8_UNORM;
case VK_FORMAT_B8G8R8_SRGB:
return VK_FORMAT_B8G8R8_UNORM;
case VK_FORMAT_R8G8B8A8_SRGB:
return VK_FORMAT_R8G8B8A8_UNORM;
case VK_FORMAT_B8G8R8A8_SRGB:
return VK_FORMAT_B8G8R8A8_UNORM;
case VK_FORMAT_BC1_RGB_SRGB_BLOCK:
return VK_FORMAT_BC1_RGB_UNORM_BLOCK;
case VK_FORMAT_BC1_RGBA_SRGB_BLOCK:
return VK_FORMAT_BC1_RGBA_UNORM_BLOCK;
case VK_FORMAT_BC2_SRGB_BLOCK:
return VK_FORMAT_BC2_UNORM_BLOCK;
case VK_FORMAT_BC3_SRGB_BLOCK:
return VK_FORMAT_BC3_UNORM_BLOCK;
case VK_FORMAT_BC7_SRGB_BLOCK:
return VK_FORMAT_BC7_UNORM_BLOCK;
case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
return VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK;
case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
return VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK;
case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
return VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK;
case VK_FORMAT_ASTC_4x4_SRGB_BLOCK:
return VK_FORMAT_ASTC_4x4_UNORM_BLOCK;
case VK_FORMAT_ASTC_5x4_SRGB_BLOCK:
return VK_FORMAT_ASTC_5x4_UNORM_BLOCK;
case VK_FORMAT_ASTC_5x5_SRGB_BLOCK:
return VK_FORMAT_ASTC_5x5_UNORM_BLOCK;
case VK_FORMAT_ASTC_6x5_SRGB_BLOCK:
return VK_FORMAT_ASTC_6x5_UNORM_BLOCK;
case VK_FORMAT_ASTC_6x6_SRGB_BLOCK:
return VK_FORMAT_ASTC_6x6_UNORM_BLOCK;
case VK_FORMAT_ASTC_8x5_SRGB_BLOCK:
return VK_FORMAT_ASTC_8x5_UNORM_BLOCK;
case VK_FORMAT_ASTC_8x6_SRGB_BLOCK:
return VK_FORMAT_ASTC_8x6_UNORM_BLOCK;
case VK_FORMAT_ASTC_8x8_SRGB_BLOCK:
return VK_FORMAT_ASTC_8x8_UNORM_BLOCK;
case VK_FORMAT_ASTC_10x5_SRGB_BLOCK:
return VK_FORMAT_ASTC_10x5_UNORM_BLOCK;
case VK_FORMAT_ASTC_10x6_SRGB_BLOCK:
return VK_FORMAT_ASTC_10x6_UNORM_BLOCK;
case VK_FORMAT_ASTC_10x8_SRGB_BLOCK:
return VK_FORMAT_ASTC_10x8_UNORM_BLOCK;
case VK_FORMAT_ASTC_10x10_SRGB_BLOCK:
return VK_FORMAT_ASTC_10x10_UNORM_BLOCK;
case VK_FORMAT_ASTC_12x10_SRGB_BLOCK:
return VK_FORMAT_ASTC_12x10_UNORM_BLOCK;
case VK_FORMAT_ASTC_12x12_SRGB_BLOCK:
return VK_FORMAT_ASTC_12x12_UNORM_BLOCK;
default:
return VK_FORMAT_UNDEFINED;
}
}
ANGLE_INLINE bool IsNonLinearFormat(VkFormat format)
{
return ConvertToLinear(format) != VK_FORMAT_UNDEFINED;
}
ANGLE_INLINE bool IsOverridableLinearFormat(VkFormat format)
{
return ConvertToNonLinear(format) != VK_FORMAT_UNDEFINED;
}
ANGLE_INLINE bool IsLinearFormat(VkFormat format)
{
return !IsNonLinearFormat(format);
}
} // namespace vk
} // namespace rx
#endif // LIBANGLE_RENDERER_VULKAN_VK_FORMAT_UTILS_H_
......@@ -36,6 +36,8 @@ constexpr VkBufferUsageFlags kStagingBufferFlags =
VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
constexpr size_t kStagingBufferSize = 1024 * 16;
constexpr VkImageCreateFlags kVkImageCreateFlagsNone = 0;
using StagingBufferOffsetArray = std::array<VkDeviceSize, 2>;
struct TextureUnit final
......@@ -1052,6 +1054,7 @@ class ImageHelper final : public Resource, public angle::Subject
const Format &format,
GLint samples,
VkImageUsageFlags usage,
VkImageCreateFlags additionalCreateFlags,
ImageLayout initialLayout,
const void *externalImageCreateInfo,
uint32_t baseLevel,
......@@ -1076,6 +1079,16 @@ class ImageHelper final : public Resource, public angle::Subject
uint32_t levelCount,
uint32_t baseArrayLayer,
uint32_t layerCount) const;
angle::Result initLayerImageViewImpl(Context *context,
gl::TextureType textureType,
VkImageAspectFlags aspectMask,
const gl::SwizzleState &swizzleMap,
ImageView *imageViewOut,
uint32_t baseMipLevel,
uint32_t levelCount,
uint32_t baseArrayLayer,
uint32_t layerCount,
VkFormat imageFormat) const;
angle::Result initImageView(Context *context,
gl::TextureType textureType,
VkImageAspectFlags aspectMask,
......@@ -1505,14 +1518,26 @@ class ImageViewHelper : angle::NonCopyable
void release(RendererVk *renderer);
void destroy(VkDevice device);
const ImageView &getReadImageView() const { return mReadImageView; }
const ImageView &getFetchImageView() const { return mFetchImageView; }
const ImageView &getLinearReadImageView() const { return mLinearReadImageView; }
const ImageView &getNonLinearReadImageView() const { return mNonLinearReadImageView; }
const ImageView &getLinearFetchImageView() const { return mLinearFetchImageView; }
const ImageView &getNonLinearFetchImageView() const { return mNonLinearFetchImageView; }
const ImageView &getStencilReadImageView() const { return mStencilReadImageView; }
const ImageView &getReadImageView() const
{
return mLinearColorspace ? mLinearReadImageView : mNonLinearReadImageView;
}
const ImageView &getFetchImageView() const
{
return mLinearColorspace ? mLinearFetchImageView : mNonLinearFetchImageView;
}
// Used when initialized RenderTargets.
bool hasStencilReadImageView() const { return mStencilReadImageView.valid(); }
bool hasFetchImageView() const { return mFetchImageView.valid(); }
bool hasFetchImageView() const { return getFetchImageView().valid(); }
// Store reference to usage in graph.
void retain(ResourceUseList *resourceUseList) const { resourceUseList->add(mUse); }
......@@ -1528,6 +1553,17 @@ class ImageViewHelper : angle::NonCopyable
uint32_t baseLayer,
uint32_t layerCount);
// Create SRGB-reinterpreted read views
angle::Result initSRGBReadViews(ContextVk *contextVk,
gl::TextureType viewType,
const ImageHelper &image,
const Format &format,
const gl::SwizzleState &swizzleState,
uint32_t baseLevel,
uint32_t levelCount,
uint32_t baseLayer,
uint32_t layerCount);
// Creates a view with all layers of the level.
angle::Result getLevelDrawImageView(ContextVk *contextVk,
gl::TextureType viewType,
......@@ -1544,14 +1580,27 @@ class ImageViewHelper : angle::NonCopyable
const ImageView **imageViewOut);
private:
ImageView &getReadImageView()
{
return mLinearColorspace ? mLinearReadImageView : mNonLinearReadImageView;
}
ImageView &getFetchImageView()
{
return mLinearColorspace ? mLinearFetchImageView : mNonLinearFetchImageView;
}
// Lifetime.
SharedResourceUse mUse;
// Read views.
ImageView mReadImageView;
ImageView mFetchImageView;
// Read views
ImageView mLinearReadImageView;
ImageView mNonLinearReadImageView;
ImageView mLinearFetchImageView;
ImageView mNonLinearFetchImageView;
ImageView mStencilReadImageView;
bool mLinearColorspace;
// Draw views.
ImageViewVector mLevelDrawImageViews;
LayerLevelImageViewVector mLayerLevelDrawImageViews;
......
......@@ -394,6 +394,29 @@ bool ValidateTextureSRGBDecodeValue(const Context *context, const ParamType *par
return true;
}
template <typename ParamType>
bool ValidateTextureSRGBOverrideValue(const Context *context, const ParamType *params)
{
if (!context->getExtensions().textureSRGBOverride)
{
context->validationError(GL_INVALID_ENUM, kExtensionNotEnabled);
return false;
}
switch (ConvertToGLenum(params[0]))
{
case GL_SRGB:
case GL_NONE:
break;
default:
context->validationError(GL_INVALID_ENUM, kUnknownParameter);
return false;
}
return true;
}
bool ValidateTextureMaxAnisotropyExtensionEnabled(const Context *context)
{
if (!context->getExtensions().textureFilterAnisotropic)
......@@ -6152,6 +6175,13 @@ bool ValidateTexParameterBase(const Context *context,
}
break;
case GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT:
if (!ValidateTextureSRGBOverrideValue(context, params))
{
return false;
}
break;
case GL_GENERATE_MIPMAP:
if (context->getClientMajorVersion() > 1)
{
......
......@@ -10,6 +10,10 @@
namespace angle
{
// These two colors are equivelent in different colorspaces
constexpr GLColor kLinearColor(64, 127, 191, 255);
constexpr GLColor kNonlinearColor(13, 54, 133, 255);
class SRGBTextureTest : public ANGLETest
{
protected:
......@@ -245,8 +249,8 @@ TEST_P(SRGBTextureTest, SRGBDecodeTextureParameter)
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_sRGB_decode"));
GLColor linearColor(64, 127, 191, 255);
GLColor srgbColor(13, 54, 133, 255);
GLColor linearColor = kLinearColor;
GLColor srgbColor = kNonlinearColor;
GLTexture tex;
glBindTexture(GL_TEXTURE_2D, tex.get());
......@@ -269,14 +273,78 @@ TEST_P(SRGBTextureTest, SRGBDecodeTextureParameter)
EXPECT_PIXEL_COLOR_NEAR(0, 0, linearColor, 1.0);
}
// Test basic functionality of SRGB override using the texture parameter
TEST_P(SRGBTextureTest, SRGBOverrideTextureParameter)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_sRGB_override"));
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();
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);
}
// 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
// the value of TEXTURE_FORMAT_SRGB_OVERRIDE_EXT is ignored."
TEST_P(SRGBTextureTest, SRGBOverrideTextureParameterNoop)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_sRGB_override"));
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_sRGB") || 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);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT, GL_NONE);
ASSERT_GL_NO_ERROR();
glUseProgram(mProgram);
glUniform1i(mTextureLocation, 0);
glDisable(GL_DEPTH_TEST);
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_SRGB);
drawQuad(mProgram, "position", 0.5f);
EXPECT_PIXEL_COLOR_NEAR(0, 0, srgbColor, 1.0);
}
// Test basic functionality of SRGB decode using the sampler parameter
TEST_P(SRGBTextureTest, SRGBDecodeSamplerParameter)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_sRGB_decode") ||
getClientMajorVersion() < 3);
GLColor linearColor(64, 127, 191, 255);
GLColor srgbColor(13, 54, 133, 255);
GLColor linearColor = kLinearColor;
GLColor srgbColor = kNonlinearColor;
GLTexture tex;
glBindTexture(GL_TEXTURE_2D, tex.get());
......
......@@ -72,7 +72,7 @@ class TextureSamplingBenchmark : public ANGLERenderTest,
void destroyBenchmark() override;
void drawBenchmark() override;
private:
protected:
void initShaders();
void initVertexBuffer();
void initTextures();
......@@ -258,6 +258,52 @@ void TextureSamplingBenchmark::drawBenchmark()
ASSERT_GL_NO_ERROR();
}
// Identical to TextureSamplingBenchmark, but enables and then disables
// EXT_texture_format_sRGB_override during initialization. This should force the internal texture
// representation to use VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT, which is expected to carry a
// performance penalty. This penalty can be quantified by comparing the results of this test with
// the results from TextureSamplingBenchmark
class TextureSamplingMutableFormatBenchmark : public TextureSamplingBenchmark
{
public:
void initializeBenchmark() override;
protected:
void initTextures();
};
void TextureSamplingMutableFormatBenchmark::initializeBenchmark()
{
if (!IsGLExtensionEnabled("GL_EXT_texture_sRGB_override"))
{
FAIL() << "GL_EXT_texture_sRGB_override not supported!" << std::endl;
}
TextureSamplingBenchmark::initializeBenchmark();
initTextures();
}
void TextureSamplingMutableFormatBenchmark::initTextures()
{
TextureSamplingBenchmark::initTextures();
for (unsigned int i = 0; i < mTextures.size(); ++i)
{
glActiveTexture(GL_TEXTURE0 + i);
glBindTexture(GL_TEXTURE_2D, mTextures[i]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT, GL_SRGB);
}
// Force a state update
drawBenchmark();
for (unsigned int i = 0; i < mTextures.size(); ++i)
{
glActiveTexture(GL_TEXTURE0 + i);
glBindTexture(GL_TEXTURE_2D, mTextures[i]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT, GL_NONE);
}
}
TextureSamplingParams D3D11Params()
{
TextureSamplingParams params;
......@@ -293,8 +339,15 @@ TEST_P(TextureSamplingBenchmark, Run)
run();
}
TEST_P(TextureSamplingMutableFormatBenchmark, Run)
{
run();
}
ANGLE_INSTANTIATE_TEST(TextureSamplingBenchmark,
D3D11Params(),
D3D9Params(),
OpenGLOrGLESParams(),
VulkanParams());
ANGLE_INSTANTIATE_TEST(TextureSamplingMutableFormatBenchmark, VulkanParams());
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