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); ...@@ -228,6 +228,15 @@ const char *GetDebugMessageSourceString(GLenum source);
const char *GetDebugMessageTypeString(GLenum type); const char *GetDebugMessageTypeString(GLenum type);
const char *GetDebugMessageSeverityString(GLenum severity); 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 gl
namespace egl namespace egl
......
...@@ -982,6 +982,7 @@ const ExtensionInfoMap &GetExtensionInfoMap() ...@@ -982,6 +982,7 @@ const ExtensionInfoMap &GetExtensionInfoMap()
map["GL_CHROMIUM_bind_generates_resource"] = esOnlyExtension(&Extensions::bindGeneratesResource); map["GL_CHROMIUM_bind_generates_resource"] = esOnlyExtension(&Extensions::bindGeneratesResource);
map["GL_ANGLE_robust_client_memory"] = esOnlyExtension(&Extensions::robustClientMemory); map["GL_ANGLE_robust_client_memory"] = esOnlyExtension(&Extensions::robustClientMemory);
map["GL_EXT_texture_sRGB_decode"] = esOnlyExtension(&Extensions::textureSRGBDecode); 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_EXT_sRGB_write_control"] = esOnlyExtension(&Extensions::sRGBWriteControl);
map["GL_CHROMIUM_color_buffer_float_rgb"] = enableableExtension(&Extensions::colorBufferFloatRGB); map["GL_CHROMIUM_color_buffer_float_rgb"] = enableableExtension(&Extensions::colorBufferFloatRGB);
map["GL_CHROMIUM_color_buffer_float_rgba"] = enableableExtension(&Extensions::colorBufferFloatRGBA); map["GL_CHROMIUM_color_buffer_float_rgba"] = enableableExtension(&Extensions::colorBufferFloatRGBA);
......
...@@ -492,6 +492,9 @@ struct Extensions ...@@ -492,6 +492,9 @@ struct Extensions
// GL_EXT_texture_sRGB_decode // GL_EXT_texture_sRGB_decode
bool textureSRGBDecode = false; bool textureSRGBDecode = false;
// GL_EXT_texture_sRGB_override
bool textureSRGBOverride = false;
// GL_EXT_sRGB_write_control // GL_EXT_sRGB_write_control
bool sRGBWriteControl = false; bool sRGBWriteControl = false;
......
...@@ -95,6 +95,7 @@ bool SwizzleState::operator!=(const SwizzleState &other) const ...@@ -95,6 +95,7 @@ bool SwizzleState::operator!=(const SwizzleState &other) const
TextureState::TextureState(TextureType type) TextureState::TextureState(TextureType type)
: mType(type), : mType(type),
mSamplerState(SamplerState::CreateDefaultForTarget(type)), mSamplerState(SamplerState::CreateDefaultForTarget(type)),
mSrgbOverride(SrgbOverride::Default),
mBaseLevel(0), mBaseLevel(0),
mMaxLevel(1000), mMaxLevel(1000),
mDepthStencilTextureMode(GL_DEPTH_COMPONENT), mDepthStencilTextureMode(GL_DEPTH_COMPONENT),
...@@ -859,6 +860,22 @@ GLenum Texture::getSRGBDecode() const ...@@ -859,6 +860,22 @@ GLenum Texture::getSRGBDecode() const
return mState.mSamplerState.getSRGBDecode(); 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 const SamplerState &Texture::getSamplerState() const
{ {
return mState.mSamplerState; return mState.mSamplerState;
......
...@@ -151,6 +151,8 @@ class TextureState final : private angle::NonCopyable ...@@ -151,6 +151,8 @@ class TextureState final : private angle::NonCopyable
return getBindingCount(contextID).imageBindingCount > 0; 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. // Returns the desc of the base level. Only valid for cube-complete/mip-complete textures.
const ImageDesc &getBaseLevelDesc() const; const ImageDesc &getBaseLevelDesc() const;
...@@ -216,6 +218,8 @@ class TextureState final : private angle::NonCopyable ...@@ -216,6 +218,8 @@ class TextureState final : private angle::NonCopyable
SamplerState mSamplerState; SamplerState mSamplerState;
SrgbOverride mSrgbOverride;
GLuint mBaseLevel; GLuint mBaseLevel;
GLuint mMaxLevel; GLuint mMaxLevel;
...@@ -308,6 +312,9 @@ class Texture final : public RefCountObject<TextureID>, ...@@ -308,6 +312,9 @@ class Texture final : public RefCountObject<TextureID>,
void setSRGBDecode(const Context *context, GLenum sRGBDecode); void setSRGBDecode(const Context *context, GLenum sRGBDecode);
GLenum getSRGBDecode() const; GLenum getSRGBDecode() const;
void setSRGBOverride(const Context *context, GLenum sRGBOverride);
GLenum getSRGBOverride() const;
const SamplerState &getSamplerState() const; const SamplerState &getSamplerState() const;
angle::Result setBaseLevel(const Context *context, GLuint baseLevel); angle::Result setBaseLevel(const Context *context, GLuint baseLevel);
...@@ -549,6 +556,7 @@ class Texture final : public RefCountObject<TextureID>, ...@@ -549,6 +556,7 @@ class Texture final : public RefCountObject<TextureID>,
DIRTY_BIT_COMPARE_MODE, DIRTY_BIT_COMPARE_MODE,
DIRTY_BIT_COMPARE_FUNC, DIRTY_BIT_COMPARE_FUNC,
DIRTY_BIT_SRGB_DECODE, DIRTY_BIT_SRGB_DECODE,
DIRTY_BIT_SRGB_OVERRIDE,
DIRTY_BIT_BORDER_COLOR, DIRTY_BIT_BORDER_COLOR,
// Texture state // Texture state
......
...@@ -304,6 +304,9 @@ void QueryTexParameterBase(const Context *context, ...@@ -304,6 +304,9 @@ void QueryTexParameterBase(const Context *context,
case GL_TEXTURE_SRGB_DECODE_EXT: case GL_TEXTURE_SRGB_DECODE_EXT:
*params = CastFromGLintStateValue<ParamType>(pname, texture->getSRGBDecode()); *params = CastFromGLintStateValue<ParamType>(pname, texture->getSRGBDecode());
break; break;
case GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT:
*params = CastFromGLintStateValue<ParamType>(pname, texture->getSRGBOverride());
break;
case GL_DEPTH_STENCIL_TEXTURE_MODE: case GL_DEPTH_STENCIL_TEXTURE_MODE:
*params = *params =
CastFromGLintStateValue<ParamType>(pname, texture->getDepthStencilTextureMode()); CastFromGLintStateValue<ParamType>(pname, texture->getDepthStencilTextureMode());
...@@ -432,6 +435,9 @@ void SetTexParameterBase(Context *context, Texture *texture, GLenum pname, const ...@@ -432,6 +435,9 @@ void SetTexParameterBase(Context *context, Texture *texture, GLenum pname, const
case GL_TEXTURE_SRGB_DECODE_EXT: case GL_TEXTURE_SRGB_DECODE_EXT:
texture->setSRGBDecode(context, ConvertToGLenum(pname, params[0])); texture->setSRGBDecode(context, ConvertToGLenum(pname, params[0]));
break; break;
case GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT:
texture->setSRGBOverride(context, ConvertToGLenum(pname, params[0]));
break;
case GL_TEXTURE_CROP_RECT_OES: case GL_TEXTURE_CROP_RECT_OES:
texture->setCrop(gl::Rectangle(ConvertTexParam<isGLfixed, GLint>(pname, params[0]), texture->setCrop(gl::Rectangle(ConvertTexParam<isGLfixed, GLint>(pname, params[0]),
ConvertTexParam<isGLfixed, GLint>(pname, params[1]), ConvertTexParam<isGLfixed, GLint>(pname, params[1]),
......
...@@ -196,10 +196,10 @@ angle::Result MemoryObjectVk::createImage(ContextVk *contextVk, ...@@ -196,10 +196,10 @@ angle::Result MemoryObjectVk::createImage(ContextVk *contextVk,
// //
// If the content is not already defined, the first operation may not be a // If the content is not already defined, the first operation may not be a
// glWaitSemaphore, but in this case undefined layout is appropriate. // glWaitSemaphore, but in this case undefined layout is appropriate.
ANGLE_TRY(image->initExternal(contextVk, type, vkExtents, vkFormat, 1, imageUsageFlags, ANGLE_TRY(image->initExternal(
vk::ImageLayout::Undefined, &externalMemoryImageCreateInfo, 0, contextVk, type, vkExtents, vkFormat, 1, imageUsageFlags, vk::kVkImageCreateFlagsNone,
static_cast<uint32_t>(levels) - 1, static_cast<uint32_t>(levels), vk::ImageLayout::Undefined, &externalMemoryImageCreateInfo, 0,
layerCount)); static_cast<uint32_t>(levels) - 1, static_cast<uint32_t>(levels), layerCount));
VkMemoryRequirements externalMemoryRequirements; VkMemoryRequirements externalMemoryRequirements;
image->getImage().getMemoryRequirements(renderer->getDevice(), &externalMemoryRequirements); image->getImage().getMemoryRequirements(renderer->getDevice(), &externalMemoryRequirements);
......
...@@ -123,6 +123,7 @@ TextureVk::TextureVk(const gl::TextureState &state, RendererVk *renderer) ...@@ -123,6 +123,7 @@ TextureVk::TextureVk(const gl::TextureState &state, RendererVk *renderer)
mImage(nullptr), mImage(nullptr),
mStagingBufferInitialSize(vk::kStagingBufferSize), mStagingBufferInitialSize(vk::kStagingBufferSize),
mImageUsageFlags(0), mImageUsageFlags(0),
mImageCreateFlags(0),
mImageObserverBinding(this, kTextureImageSubjectIndex) mImageObserverBinding(this, kTextureImageSubjectIndex)
{} {}
...@@ -1209,7 +1210,7 @@ angle::Result TextureVk::copyAndStageImageSubresource(ContextVk *contextVk, ...@@ -1209,7 +1210,7 @@ angle::Result TextureVk::copyAndStageImageSubresource(ContextVk *contextVk,
&layerCount); &layerCount);
gl::Box area(offset.x, offset.y, offset.z, updatedExtents.width, updatedExtents.height, gl::Box area(offset.x, offset.y, offset.z, updatedExtents.width, updatedExtents.height,
updatedExtents.depth); updatedExtents.depth);
// TODO: Refactor TextureVk::changeLevels() to avoid this workaround. // TODO: Refactor TextureVk::respecifyImageAttributesAndLevels() to avoid this workaround.
if (ignoreLayerCount) if (ignoreLayerCount)
{ {
layerCount = 1; layerCount = 1;
...@@ -1278,13 +1279,19 @@ angle::Result TextureVk::updateBaseMaxLevels(ContextVk *contextVk, ...@@ -1278,13 +1279,19 @@ angle::Result TextureVk::updateBaseMaxLevels(ContextVk *contextVk,
return angle::Result::Continue; return angle::Result::Continue;
} }
return changeLevels(contextVk, previousBaseLevel, baseLevel, maxLevel); return respecifyImageAttributesAndLevels(contextVk, previousBaseLevel, baseLevel, maxLevel);
} }
angle::Result TextureVk::changeLevels(ContextVk *contextVk, angle::Result TextureVk::respecifyImageAttributes(ContextVk *contextVk)
GLuint previousBaseLevel, {
GLuint baseLevel, return respecifyImageAttributesAndLevels(contextVk, mImage->getBaseLevel(),
GLuint maxLevel) 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. // 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
...@@ -1320,8 +1327,8 @@ angle::Result TextureVk::changeLevels(ContextVk *contextVk, ...@@ -1320,8 +1327,8 @@ angle::Result TextureVk::changeLevels(ContextVk *contextVk,
// layer/level, we don't need to propagate any data from this image. // 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 // 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 // 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 // staged by previous calls to respecifyImageAttributesAndLevels that didn't fit
// new vkImage. // into the new vkImage.
continue; continue;
} }
...@@ -1475,6 +1482,9 @@ angle::Result TextureVk::syncState(const gl::Context *context, ...@@ -1475,6 +1482,9 @@ angle::Result TextureVk::syncState(const gl::Context *context,
{ {
ContextVk *contextVk = vk::GetImpl(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. // 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 (dirtyBits.test(gl::Texture::DIRTY_BIT_BOUND_AS_IMAGE))
{ {
...@@ -1482,11 +1492,23 @@ angle::Result TextureVk::syncState(const gl::Context *context, ...@@ -1482,11 +1492,23 @@ angle::Result TextureVk::syncState(const gl::Context *context,
if (!(mImageUsageFlags & VK_IMAGE_USAGE_STORAGE_BIT)) if (!(mImageUsageFlags & VK_IMAGE_USAGE_STORAGE_BIT))
{ {
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 // Set base and max level before initializing the image
if (dirtyBits.test(gl::Texture::DIRTY_BIT_MAX_LEVEL) || if (dirtyBits.test(gl::Texture::DIRTY_BIT_MAX_LEVEL) ||
dirtyBits.test(gl::Texture::DIRTY_BIT_BASE_LEVEL)) dirtyBits.test(gl::Texture::DIRTY_BIT_BASE_LEVEL))
...@@ -1516,7 +1538,8 @@ angle::Result TextureVk::syncState(const gl::Context *context, ...@@ -1516,7 +1538,8 @@ angle::Result TextureVk::syncState(const gl::Context *context,
if (localBits.test(gl::Texture::DIRTY_BIT_SWIZZLE_RED) || if (localBits.test(gl::Texture::DIRTY_BIT_SWIZZLE_RED) ||
localBits.test(gl::Texture::DIRTY_BIT_SWIZZLE_GREEN) || localBits.test(gl::Texture::DIRTY_BIT_SWIZZLE_GREEN) ||
localBits.test(gl::Texture::DIRTY_BIT_SWIZZLE_BLUE) || 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()) if (mImage && mImage->valid())
{ {
...@@ -1576,6 +1599,12 @@ const vk::ImageView &TextureVk::getReadImageViewAndRecordUse(ContextVk *contextV ...@@ -1576,6 +1599,12 @@ const vk::ImageView &TextureVk::getReadImageViewAndRecordUse(ContextVk *contextV
return mImageViews.getStencilReadImageView(); return mImageViews.getStencilReadImageView();
} }
if (mState.getSRGBOverride() == gl::SrgbOverride::Enabled)
{
ASSERT(mImageViews.getNonLinearReadImageView().valid());
return mImageViews.getNonLinearReadImageView();
}
return mImageViews.getReadImageView(); return mImageViews.getReadImageView();
} }
...@@ -1587,6 +1616,13 @@ const vk::ImageView &TextureVk::getFetchImageViewAndRecordUse(ContextVk *context ...@@ -1587,6 +1616,13 @@ 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(!mImageViews.hasStencilReadImageView() || !mImageViews.hasFetchImageView()); ASSERT(!mImageViews.hasStencilReadImageView() || !mImageViews.hasFetchImageView());
if (mState.getSRGBOverride() == gl::SrgbOverride::Enabled)
{
return (mImageViews.hasFetchImageView() ? mImageViews.getNonLinearFetchImageView()
: mImageViews.getNonLinearReadImageView());
}
return (mImageViews.hasFetchImageView() ? mImageViews.getFetchImageView() return (mImageViews.hasFetchImageView() ? mImageViews.getFetchImageView()
: mImageViews.getReadImageView()); : mImageViews.getReadImageView());
} }
...@@ -1635,9 +1671,10 @@ angle::Result TextureVk::initImage(ContextVk *contextVk, ...@@ -1635,9 +1671,10 @@ angle::Result TextureVk::initImage(ContextVk *contextVk,
gl_vk::GetExtentsAndLayerCount(mState.getType(), extents, &vkExtent, &layerCount); gl_vk::GetExtentsAndLayerCount(mState.getType(), extents, &vkExtent, &layerCount);
GLint samples = mState.getBaseLevelDesc().samples ? mState.getBaseLevelDesc().samples : 1; GLint samples = mState.getBaseLevelDesc().samples ? mState.getBaseLevelDesc().samples : 1;
ANGLE_TRY(mImage->init(contextVk, mState.getType(), vkExtent, format, samples, mImageUsageFlags, ANGLE_TRY(mImage->initExternal(
mState.getEffectiveBaseLevel(), mState.getEffectiveMaxLevel(), contextVk, mState.getType(), vkExtent, format, samples, mImageUsageFlags, mImageCreateFlags,
levelCount, layerCount)); rx::vk::ImageLayout::Undefined, nullptr, mState.getEffectiveBaseLevel(),
mState.getEffectiveMaxLevel(), levelCount, layerCount));
const VkMemoryPropertyFlags flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; const VkMemoryPropertyFlags flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
...@@ -1665,8 +1702,17 @@ angle::Result TextureVk::initImageViews(ContextVk *contextVk, ...@@ -1665,8 +1702,17 @@ angle::Result TextureVk::initImageViews(ContextVk *contextVk,
gl::SwizzleState mappedSwizzle; gl::SwizzleState mappedSwizzle;
MapSwizzleState(contextVk, format, sized, mState.getSwizzleState(), &mappedSwizzle); MapSwizzleState(contextVk, format, sized, mState.getSwizzleState(), &mappedSwizzle);
return mImageViews.initReadViews(contextVk, mState.getType(), *mImage, format, mappedSwizzle, ANGLE_TRY(mImageViews.initReadViews(contextVk, mState.getType(), *mImage, format, mappedSwizzle,
baseLevel, levelCount, baseLayer, layerCount); 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) void TextureVk::releaseImage(ContextVk *contextVk)
......
...@@ -376,11 +376,13 @@ class TextureVk : public TextureImpl, public angle::ObserverInterface ...@@ -376,11 +376,13 @@ class TextureVk : public TextureImpl, public angle::ObserverInterface
const gl::InternalFormat &getImplementationSizedFormat(const gl::Context *context) const; const gl::InternalFormat &getImplementationSizedFormat(const gl::Context *context) const;
const vk::Format &getBaseLevelFormat(RendererVk *renderer) const; const vk::Format &getBaseLevelFormat(RendererVk *renderer) const;
// Re-create the image. // Queues a flush of any modified image attributes. The image will be reallocated with its new
angle::Result changeLevels(ContextVk *contextVk, // attributes at the next opportunity.
GLuint previousBaseLevel, angle::Result respecifyImageAttributes(ContextVk *contextVk);
GLuint baseLevel, angle::Result respecifyImageAttributesAndLevels(ContextVk *contextVk,
GLuint maxLevel); GLuint previousBaseLevel,
GLuint baseLevel,
GLuint maxLevel);
// 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, GLuint baseLevel, GLuint maxLevel); angle::Result updateBaseMaxLevels(ContextVk *contextVk, GLuint baseLevel, GLuint maxLevel);
...@@ -428,6 +430,9 @@ class TextureVk : public TextureImpl, public angle::ObserverInterface ...@@ -428,6 +430,9 @@ class TextureVk : public TextureImpl, public angle::ObserverInterface
// The created vkImage usage flag. // The created vkImage usage flag.
VkImageUsageFlags mImageUsageFlags; VkImageUsageFlags mImageUsageFlags;
// Additional image create flags
VkImageCreateFlags mImageCreateFlags;
angle::ObserverBinding mImageObserverBinding; angle::ObserverBinding mImageObserverBinding;
}; };
......
...@@ -126,9 +126,9 @@ angle::Result HardwareBufferImageSiblingVkAndroid::initImpl(DisplayVk *displayVk ...@@ -126,9 +126,9 @@ angle::Result HardwareBufferImageSiblingVkAndroid::initImpl(DisplayVk *displayVk
gl_vk::GetExtent(mSize, &vkExtents); gl_vk::GetExtent(mSize, &vkExtents);
mImage = new vk::ImageHelper(); mImage = new vk::ImageHelper();
ANGLE_TRY(mImage->initExternal(displayVk, gl::TextureType::_2D, vkExtents, vkFormat, 1, usage, ANGLE_TRY(mImage->initExternal(
vk::ImageLayout::ExternalPreInitialized, displayVk, gl::TextureType::_2D, vkExtents, vkFormat, 1, usage, vk::kVkImageCreateFlagsNone,
&externalMemoryImageCreateInfo, 0, 0, 1, 1)); vk::ImageLayout::ExternalPreInitialized, &externalMemoryImageCreateInfo, 0, 0, 1, 1));
VkImportAndroidHardwareBufferInfoANDROID importHardwareBufferInfo = {}; VkImportAndroidHardwareBufferInfoANDROID importHardwareBufferInfo = {};
importHardwareBufferInfo.sType = VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID; importHardwareBufferInfo.sType = VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID;
......
...@@ -181,6 +181,9 @@ void RendererVk::ensureCapsInitialized() const ...@@ -181,6 +181,9 @@ void RendererVk::ensureCapsInitialized() const
mNativeExtensions.depthTextureCubeMapOES = mNativeExtensions.depthTextureCubeMapOES =
mNativeExtensions.depthTextureOES && mNativeExtensions.packedDepthStencilOES; mNativeExtensions.depthTextureOES && mNativeExtensions.packedDepthStencilOES;
// Vulkan natively supports format reinterpretation
mNativeExtensions.textureSRGBOverride = mNativeExtensions.sRGB;
mNativeExtensions.gpuShader5EXT = vk::CanSupportGPUShader5EXT(mPhysicalDeviceFeatures); mNativeExtensions.gpuShader5EXT = vk::CanSupportGPUShader5EXT(mPhysicalDeviceFeatures);
// https://vulkan.lunarg.com/doc/view/1.0.30.0/linux/vkspec.chunked/ch31s02.html // https://vulkan.lunarg.com/doc/view/1.0.30.0/linux/vkspec.chunked/ch31s02.html
......
...@@ -168,6 +168,154 @@ void MapSwizzleState(const ContextVk *contextVk, ...@@ -168,6 +168,154 @@ void MapSwizzleState(const ContextVk *contextVk,
const bool sized, const bool sized,
const gl::SwizzleState &swizzleState, const gl::SwizzleState &swizzleState,
gl::SwizzleState *swizzleStateOut); 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 } // namespace rx
#endif // LIBANGLE_RENDERER_VULKAN_VK_FORMAT_UTILS_H_ #endif // LIBANGLE_RENDERER_VULKAN_VK_FORMAT_UTILS_H_
...@@ -36,6 +36,8 @@ constexpr VkBufferUsageFlags kStagingBufferFlags = ...@@ -36,6 +36,8 @@ constexpr VkBufferUsageFlags kStagingBufferFlags =
VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
constexpr size_t kStagingBufferSize = 1024 * 16; constexpr size_t kStagingBufferSize = 1024 * 16;
constexpr VkImageCreateFlags kVkImageCreateFlagsNone = 0;
using StagingBufferOffsetArray = std::array<VkDeviceSize, 2>; using StagingBufferOffsetArray = std::array<VkDeviceSize, 2>;
struct TextureUnit final struct TextureUnit final
...@@ -1052,6 +1054,7 @@ class ImageHelper final : public Resource, public angle::Subject ...@@ -1052,6 +1054,7 @@ class ImageHelper final : public Resource, public angle::Subject
const Format &format, const Format &format,
GLint samples, GLint samples,
VkImageUsageFlags usage, VkImageUsageFlags usage,
VkImageCreateFlags additionalCreateFlags,
ImageLayout initialLayout, ImageLayout initialLayout,
const void *externalImageCreateInfo, const void *externalImageCreateInfo,
uint32_t baseLevel, uint32_t baseLevel,
...@@ -1076,6 +1079,16 @@ class ImageHelper final : public Resource, public angle::Subject ...@@ -1076,6 +1079,16 @@ class ImageHelper final : public Resource, public angle::Subject
uint32_t levelCount, uint32_t levelCount,
uint32_t baseArrayLayer, uint32_t baseArrayLayer,
uint32_t layerCount) const; 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, angle::Result initImageView(Context *context,
gl::TextureType textureType, gl::TextureType textureType,
VkImageAspectFlags aspectMask, VkImageAspectFlags aspectMask,
...@@ -1505,14 +1518,26 @@ class ImageViewHelper : angle::NonCopyable ...@@ -1505,14 +1518,26 @@ class ImageViewHelper : angle::NonCopyable
void release(RendererVk *renderer); void release(RendererVk *renderer);
void destroy(VkDevice device); void destroy(VkDevice device);
const ImageView &getReadImageView() const { return mReadImageView; } const ImageView &getLinearReadImageView() const { return mLinearReadImageView; }
const ImageView &getFetchImageView() const { return mFetchImageView; } 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 &getStencilReadImageView() const { return mStencilReadImageView; }
const ImageView &getReadImageView() const
{
return mLinearColorspace ? mLinearReadImageView : mNonLinearReadImageView;
}
const ImageView &getFetchImageView() const
{
return mLinearColorspace ? mLinearFetchImageView : mNonLinearFetchImageView;
}
// Used when initialized RenderTargets. // Used when initialized RenderTargets.
bool hasStencilReadImageView() const { return mStencilReadImageView.valid(); } bool hasStencilReadImageView() const { return mStencilReadImageView.valid(); }
bool hasFetchImageView() const { return mFetchImageView.valid(); } bool hasFetchImageView() const { return getFetchImageView().valid(); }
// Store reference to usage in graph. // Store reference to usage in graph.
void retain(ResourceUseList *resourceUseList) const { resourceUseList->add(mUse); } void retain(ResourceUseList *resourceUseList) const { resourceUseList->add(mUse); }
...@@ -1528,6 +1553,17 @@ class ImageViewHelper : angle::NonCopyable ...@@ -1528,6 +1553,17 @@ class ImageViewHelper : angle::NonCopyable
uint32_t baseLayer, uint32_t baseLayer,
uint32_t layerCount); 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. // Creates a view with all layers of the level.
angle::Result getLevelDrawImageView(ContextVk *contextVk, angle::Result getLevelDrawImageView(ContextVk *contextVk,
gl::TextureType viewType, gl::TextureType viewType,
...@@ -1544,14 +1580,27 @@ class ImageViewHelper : angle::NonCopyable ...@@ -1544,14 +1580,27 @@ class ImageViewHelper : angle::NonCopyable
const ImageView **imageViewOut); const ImageView **imageViewOut);
private: private:
ImageView &getReadImageView()
{
return mLinearColorspace ? mLinearReadImageView : mNonLinearReadImageView;
}
ImageView &getFetchImageView()
{
return mLinearColorspace ? mLinearFetchImageView : mNonLinearFetchImageView;
}
// Lifetime. // Lifetime.
SharedResourceUse mUse; SharedResourceUse mUse;
// Read views. // Read views
ImageView mReadImageView; ImageView mLinearReadImageView;
ImageView mFetchImageView; ImageView mNonLinearReadImageView;
ImageView mLinearFetchImageView;
ImageView mNonLinearFetchImageView;
ImageView mStencilReadImageView; ImageView mStencilReadImageView;
bool mLinearColorspace;
// Draw views. // Draw views.
ImageViewVector mLevelDrawImageViews; ImageViewVector mLevelDrawImageViews;
LayerLevelImageViewVector mLayerLevelDrawImageViews; LayerLevelImageViewVector mLayerLevelDrawImageViews;
......
...@@ -394,6 +394,29 @@ bool ValidateTextureSRGBDecodeValue(const Context *context, const ParamType *par ...@@ -394,6 +394,29 @@ bool ValidateTextureSRGBDecodeValue(const Context *context, const ParamType *par
return true; 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) bool ValidateTextureMaxAnisotropyExtensionEnabled(const Context *context)
{ {
if (!context->getExtensions().textureFilterAnisotropic) if (!context->getExtensions().textureFilterAnisotropic)
...@@ -6152,6 +6175,13 @@ bool ValidateTexParameterBase(const Context *context, ...@@ -6152,6 +6175,13 @@ bool ValidateTexParameterBase(const Context *context,
} }
break; break;
case GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT:
if (!ValidateTextureSRGBOverrideValue(context, params))
{
return false;
}
break;
case GL_GENERATE_MIPMAP: case GL_GENERATE_MIPMAP:
if (context->getClientMajorVersion() > 1) if (context->getClientMajorVersion() > 1)
{ {
......
...@@ -10,6 +10,10 @@ ...@@ -10,6 +10,10 @@
namespace angle 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 class SRGBTextureTest : public ANGLETest
{ {
protected: protected:
...@@ -245,8 +249,8 @@ TEST_P(SRGBTextureTest, SRGBDecodeTextureParameter) ...@@ -245,8 +249,8 @@ TEST_P(SRGBTextureTest, SRGBDecodeTextureParameter)
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_sRGB_decode")); ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_sRGB_decode"));
GLColor linearColor(64, 127, 191, 255); GLColor linearColor = kLinearColor;
GLColor srgbColor(13, 54, 133, 255); GLColor srgbColor = kNonlinearColor;
GLTexture tex; GLTexture tex;
glBindTexture(GL_TEXTURE_2D, tex.get()); glBindTexture(GL_TEXTURE_2D, tex.get());
...@@ -269,14 +273,78 @@ TEST_P(SRGBTextureTest, SRGBDecodeTextureParameter) ...@@ -269,14 +273,78 @@ TEST_P(SRGBTextureTest, SRGBDecodeTextureParameter)
EXPECT_PIXEL_COLOR_NEAR(0, 0, linearColor, 1.0); 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 basic functionality of SRGB decode using the sampler parameter
TEST_P(SRGBTextureTest, SRGBDecodeSamplerParameter) TEST_P(SRGBTextureTest, SRGBDecodeSamplerParameter)
{ {
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_sRGB_decode") || ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_sRGB_decode") ||
getClientMajorVersion() < 3); getClientMajorVersion() < 3);
GLColor linearColor(64, 127, 191, 255); GLColor linearColor = kLinearColor;
GLColor srgbColor(13, 54, 133, 255); GLColor srgbColor = kNonlinearColor;
GLTexture tex; GLTexture tex;
glBindTexture(GL_TEXTURE_2D, tex.get()); glBindTexture(GL_TEXTURE_2D, tex.get());
......
...@@ -72,7 +72,7 @@ class TextureSamplingBenchmark : public ANGLERenderTest, ...@@ -72,7 +72,7 @@ class TextureSamplingBenchmark : public ANGLERenderTest,
void destroyBenchmark() override; void destroyBenchmark() override;
void drawBenchmark() override; void drawBenchmark() override;
private: protected:
void initShaders(); void initShaders();
void initVertexBuffer(); void initVertexBuffer();
void initTextures(); void initTextures();
...@@ -258,6 +258,52 @@ void TextureSamplingBenchmark::drawBenchmark() ...@@ -258,6 +258,52 @@ void TextureSamplingBenchmark::drawBenchmark()
ASSERT_GL_NO_ERROR(); 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 D3D11Params()
{ {
TextureSamplingParams params; TextureSamplingParams params;
...@@ -293,8 +339,15 @@ TEST_P(TextureSamplingBenchmark, Run) ...@@ -293,8 +339,15 @@ TEST_P(TextureSamplingBenchmark, Run)
run(); run();
} }
TEST_P(TextureSamplingMutableFormatBenchmark, Run)
{
run();
}
ANGLE_INSTANTIATE_TEST(TextureSamplingBenchmark, ANGLE_INSTANTIATE_TEST(TextureSamplingBenchmark,
D3D11Params(), D3D11Params(),
D3D9Params(), D3D9Params(),
OpenGLOrGLESParams(), OpenGLOrGLESParams(),
VulkanParams()); 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