Commit df415528 by Sunny Sun Committed by Commit Bot

Vulkan: Enable VK_IMAGE_USAGE_STORAGE_BIT when it is needed

VK_IMAGE_USAGE_STORAGE_BIT is always enabled for vkImage, this increases memory bandwidth in some platforms. This CL changes the behavior to enable VK_IMAGE_USAGE_STORAGE_BIT when necessary. Bug: angleproject:3904 Test: angle_end2end_tests Test: angle_deqp_gles2_tests Change-Id: I8ffd37efa8d99d04328fa6232de0755be3273d9e Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1857799 Commit-Queue: Sunny Sun <sunny.sun@arm.com> Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 67527cb4
...@@ -165,3 +165,4 @@ Samsung Electronics, Inc. ...@@ -165,3 +165,4 @@ Samsung Electronics, Inc.
Arm Ltd. Arm Ltd.
Fei Yang Fei Yang
Xinyi He Xinyi He
Sunny Sun
...@@ -486,6 +486,7 @@ void Context::initialize() ...@@ -486,6 +486,7 @@ void Context::initialize()
mDrawDirtyObjects.set(State::DIRTY_OBJECT_TEXTURES); mDrawDirtyObjects.set(State::DIRTY_OBJECT_TEXTURES);
mDrawDirtyObjects.set(State::DIRTY_OBJECT_PROGRAM); mDrawDirtyObjects.set(State::DIRTY_OBJECT_PROGRAM);
mDrawDirtyObjects.set(State::DIRTY_OBJECT_SAMPLERS); mDrawDirtyObjects.set(State::DIRTY_OBJECT_SAMPLERS);
mDrawDirtyObjects.set(State::DIRTY_OBJECT_IMAGES);
mPathOperationDirtyObjects.set(State::DIRTY_OBJECT_DRAW_FRAMEBUFFER); mPathOperationDirtyObjects.set(State::DIRTY_OBJECT_DRAW_FRAMEBUFFER);
mPathOperationDirtyObjects.set(State::DIRTY_OBJECT_VERTEX_ARRAY); mPathOperationDirtyObjects.set(State::DIRTY_OBJECT_VERTEX_ARRAY);
......
...@@ -2881,6 +2881,10 @@ void State::setImageUnit(const Context *context, ...@@ -2881,6 +2881,10 @@ void State::setImageUnit(const Context *context,
mImageUnits[unit].format = format; mImageUnits[unit].format = format;
mDirtyBits.set(DIRTY_BIT_IMAGE_BINDINGS); mDirtyBits.set(DIRTY_BIT_IMAGE_BINDINGS);
if (texture)
{
texture->onBindImageTexture();
}
onImageStateChange(context, unit); onImageStateChange(context, unit);
} }
......
...@@ -99,6 +99,7 @@ TextureState::TextureState(TextureType type) ...@@ -99,6 +99,7 @@ TextureState::TextureState(TextureType type)
mBaseLevel(0), mBaseLevel(0),
mMaxLevel(1000), mMaxLevel(1000),
mDepthStencilTextureMode(GL_DEPTH_COMPONENT), mDepthStencilTextureMode(GL_DEPTH_COMPONENT),
mBoundAsImageTexture(false),
mImmutableFormat(false), mImmutableFormat(false),
mImmutableLevels(0), mImmutableLevels(0),
mUsage(GL_NONE), mUsage(GL_NONE),
...@@ -1908,4 +1909,14 @@ angle::Result Texture::getTexImage(const Context *context, ...@@ -1908,4 +1909,14 @@ angle::Result Texture::getTexImage(const Context *context,
return mTexture->getTexImage(context, packState, packBuffer, target, level, format, type, return mTexture->getTexImage(context, packState, packBuffer, target, level, format, type,
pixels); pixels);
} }
void Texture::onBindImageTexture()
{
if (!mState.mBoundAsImageTexture)
{
mDirtyBits.set(DIRTY_BIT_BOUND_AS_IMAGE);
mState.mBoundAsImageTexture = true;
}
}
} // namespace gl } // namespace gl
...@@ -190,6 +190,7 @@ class TextureState final : private angle::NonCopyable ...@@ -190,6 +190,7 @@ class TextureState final : private angle::NonCopyable
GLenum mDepthStencilTextureMode; GLenum mDepthStencilTextureMode;
bool mBoundAsImageTexture;
bool mImmutableFormat; bool mImmutableFormat;
GLuint mImmutableLevels; GLuint mImmutableLevels;
...@@ -412,6 +413,7 @@ class Texture final : public RefCountObject<TextureID>, ...@@ -412,6 +413,7 @@ class Texture final : public RefCountObject<TextureID>,
angle::Result setEGLImageTarget(Context *context, TextureType type, egl::Image *imageTarget); angle::Result setEGLImageTarget(Context *context, TextureType type, egl::Image *imageTarget);
angle::Result generateMipmap(Context *context); angle::Result generateMipmap(Context *context);
void onBindImageTexture();
egl::Surface *getBoundSurface() const; egl::Surface *getBoundSurface() const;
egl::Stream *getBoundStream() const; egl::Stream *getBoundStream() const;
...@@ -493,6 +495,9 @@ class Texture final : public RefCountObject<TextureID>, ...@@ -493,6 +495,9 @@ class Texture final : public RefCountObject<TextureID>,
DIRTY_BIT_MAX_LEVEL, DIRTY_BIT_MAX_LEVEL,
DIRTY_BIT_DEPTH_STENCIL_TEXTURE_MODE, DIRTY_BIT_DEPTH_STENCIL_TEXTURE_MODE,
// Image state
DIRTY_BIT_BOUND_AS_IMAGE,
// Misc // Misc
DIRTY_BIT_LABEL, DIRTY_BIT_LABEL,
DIRTY_BIT_USAGE, DIRTY_BIT_USAGE,
......
...@@ -1462,6 +1462,9 @@ angle::Result TextureGL::syncState(const gl::Context *context, ...@@ -1462,6 +1462,9 @@ angle::Result TextureGL::syncState(const gl::Context *context,
// This special dirty bit is used to signal the front-end that the implementation // This special dirty bit is used to signal the front-end that the implementation
// has local dirty bits. The real dirty bits are in mLocalDirty bits. // has local dirty bits. The real dirty bits are in mLocalDirty bits.
break; break;
case gl::Texture::DIRTY_BIT_BOUND_AS_IMAGE:
// Only used for Vulkan.
break;
default: default:
UNREACHABLE(); UNREACHABLE();
......
...@@ -107,7 +107,8 @@ TextureVk::TextureVk(const gl::TextureState &state, RendererVk *renderer) ...@@ -107,7 +107,8 @@ TextureVk::TextureVk(const gl::TextureState &state, RendererVk *renderer)
mImageLayerOffset(0), mImageLayerOffset(0),
mImageLevelOffset(0), mImageLevelOffset(0),
mImage(nullptr), mImage(nullptr),
mStagingBufferInitialSize(vk::kStagingBufferSize) mStagingBufferInitialSize(vk::kStagingBufferSize),
mImageUsageFlags(0)
{} {}
TextureVk::~TextureVk() = default; TextureVk::~TextureVk() = default;
...@@ -727,10 +728,6 @@ angle::Result TextureVk::setStorage(const gl::Context *context, ...@@ -727,10 +728,6 @@ angle::Result TextureVk::setStorage(const gl::Context *context,
{ {
releaseImage(contextVk); releaseImage(contextVk);
} }
gl::Format glFormat(internalFormat);
ANGLE_TRY(
initImage(contextVk, format, glFormat.info->sized, size, static_cast<uint32_t>(levels)));
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -867,6 +864,21 @@ angle::Result TextureVk::ensureImageAllocated(ContextVk *contextVk, const vk::Fo ...@@ -867,6 +864,21 @@ angle::Result TextureVk::ensureImageAllocated(ContextVk *contextVk, const vk::Fo
updateImageHelper(contextVk, format); updateImageHelper(contextVk, format);
} }
mImageUsageFlags = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
VK_IMAGE_USAGE_SAMPLED_BIT;
// If the image has depth/stencil support, add those as possible usage.
if (contextVk->getRenderer()->hasImageFormatFeatureBits(
format.vkImageFormat, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT))
{
mImageUsageFlags |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
}
else if (contextVk->getRenderer()->hasImageFormatFeatureBits(
format.vkImageFormat, VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT))
{
mImageUsageFlags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
}
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -1052,15 +1064,24 @@ angle::Result TextureVk::generateMipmap(const gl::Context *context) ...@@ -1052,15 +1064,24 @@ angle::Result TextureVk::generateMipmap(const gl::Context *context)
// Redefine the images with mipmaps. // Redefine the images with mipmaps.
// Copy image to the staging buffer and stage an update to the new one. // Copy image to the staging buffer and stage an update to the new one.
vk::BufferHelper *stagingBuffer = nullptr;
ANGLE_TRY(copyImageDataToStagingBuffer(contextVk, baseLevelDesc, false, ANGLE_TRY(copyImageDataToStagingBuffer(contextVk, baseLevelDesc, false,
getNativeImageLayer(0), 0, mImage->getBaseLevel())); getNativeImageLayer(0), 0, mImage->getBaseLevel(),
&stagingBuffer));
onStagingBufferChange(); onStagingBufferChange();
// Release the origin image and recreate it with new mipmap counts. // Release the origin image and recreate it with new mipmap counts.
releaseImage(contextVk); releaseImage(contextVk);
ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::FullMipChain)); ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::FullMipChain));
// Set up read dependency, we are now reading from this buffer to the new image.
if (stagingBuffer)
{
stagingBuffer->onRead(contextVk, mImage, VK_ACCESS_TRANSFER_READ_BIT);
// Different parts of the buffer might be read from or write to.
stagingBuffer->onSelfReadWrite(contextVk, VK_ACCESS_TRANSFER_READ_BIT,
VK_ACCESS_TRANSFER_WRITE_BIT);
}
} }
// Check if the image supports blit. If it does, we can do the mipmap generation on the gpu // Check if the image supports blit. If it does, we can do the mipmap generation on the gpu
// only. // only.
...@@ -1082,7 +1103,8 @@ angle::Result TextureVk::copyImageDataToStagingBuffer(ContextVk *contextVk, ...@@ -1082,7 +1103,8 @@ angle::Result TextureVk::copyImageDataToStagingBuffer(ContextVk *contextVk,
bool ignoreLayerCount, bool ignoreLayerCount,
uint32_t currentLayer, uint32_t currentLayer,
uint32_t sourceMipLevel, uint32_t sourceMipLevel,
uint32_t stagingDstMipLevel) uint32_t stagingDstMipLevel,
vk::BufferHelper **stagingBuffer)
{ {
const gl::Extents &baseLevelExtents = desc.size; const gl::Extents &baseLevelExtents = desc.size;
const gl::InternalFormat &baseLevelFormat = *desc.format.info; const gl::InternalFormat &baseLevelFormat = *desc.format.info;
...@@ -1101,18 +1123,21 @@ angle::Result TextureVk::copyImageDataToStagingBuffer(ContextVk *contextVk, ...@@ -1101,18 +1123,21 @@ angle::Result TextureVk::copyImageDataToStagingBuffer(ContextVk *contextVk,
} }
// Copy from the base level image to the staging buffer // Copy from the base level image to the staging buffer
vk::BufferHelper *stagingBuffer = nullptr;
VkDeviceSize stagingBufferOffset = 0; VkDeviceSize stagingBufferOffset = 0;
ANGLE_TRY(mImage->copyImageDataToBuffer(contextVk, sourceMipLevel, layerCount, currentLayer, ANGLE_TRY(mImage->copyImageDataToBuffer(contextVk, sourceMipLevel, layerCount, currentLayer,
area, &stagingBuffer, &stagingBufferOffset, nullptr)); area, stagingBuffer, &stagingBufferOffset, nullptr));
// Stage an update to the new image // Stage an update to the new image
size_t bufferSize = updatedExtents.width * updatedExtents.height * updatedExtents.depth * size_t bufferSize = updatedExtents.width * updatedExtents.height * updatedExtents.depth *
baseLevelFormat.pixelBytes; baseLevelFormat.pixelBytes;
ANGLE_TRY(mImage->stageSubresourceUpdateFromBuffer(contextVk, bufferSize, stagingDstMipLevel, ASSERT(*stagingBuffer);
currentLayer, layerCount, updatedExtents, ANGLE_TRY(mImage->stageSubresourceUpdateFromBuffer(
offset, stagingBuffer, stagingBufferOffset)); contextVk, bufferSize, stagingDstMipLevel, currentLayer, layerCount, updatedExtents, offset,
*stagingBuffer, stagingBufferOffset));
// Set up write dependency, we are writing to this buffer from the old image.
(*stagingBuffer)->onWrite(contextVk, mImage, 0, VK_ACCESS_TRANSFER_WRITE_BIT);
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -1122,7 +1147,10 @@ angle::Result TextureVk::setBaseLevel(const gl::Context *context, GLuint baseLev ...@@ -1122,7 +1147,10 @@ angle::Result TextureVk::setBaseLevel(const gl::Context *context, GLuint baseLev
return angle::Result::Continue; return angle::Result::Continue;
} }
angle::Result TextureVk::changeLevels(ContextVk *contextVk, GLuint baseLevel, GLuint maxLevel) angle::Result TextureVk::updateBaseMaxLevels(ContextVk *contextVk,
GLuint baseLevel,
GLuint maxLevel,
vk::BufferHelper **stagingBuffer)
{ {
if (!mImage) if (!mImage)
{ {
...@@ -1151,15 +1179,27 @@ angle::Result TextureVk::changeLevels(ContextVk *contextVk, GLuint baseLevel, GL ...@@ -1151,15 +1179,27 @@ angle::Result TextureVk::changeLevels(ContextVk *contextVk, GLuint baseLevel, GL
return angle::Result::Continue; return angle::Result::Continue;
} }
// If we get here, we already have a valid image and it needs to be recreated return changeLevels(contextVk, previousBaseLevel, baseLevel, maxLevel, stagingBuffer);
// to reflect new base or max levels. }
angle::Result TextureVk::changeLevels(ContextVk *contextVk,
GLuint previousBaseLevel,
GLuint baseLevel,
GLuint maxLevel,
vk::BufferHelper **stagingBuffer)
{
// 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
if (mImage->valid() && mImage->hasStagedUpdates())
{
vk::CommandBuffer *commandBuffer = nullptr; vk::CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(mImage->recordCommands(contextVk, &commandBuffer)); ANGLE_TRY(mImage->recordCommands(contextVk, &commandBuffer));
ANGLE_TRY(mImage->flushStagedUpdates(contextVk, getNativeImageLevel(0), mImage->getLevelCount(), ANGLE_TRY(mImage->flushStagedUpdates(contextVk, getNativeImageLevel(0),
getNativeImageLayer(0), mImage->getLayerCount(), mImage->getLevelCount(), getNativeImageLayer(0),
commandBuffer)); mImage->getLayerCount(), commandBuffer));
}
bool baseLevelChanged = baseLevel != previousBaseLevel;
// After flushing, track the new levels (they are used in the flush, hence the wait) // After flushing, track the new levels (they are used in the flush, hence the wait)
mImage->setBaseAndMaxLevels(baseLevel, maxLevel); mImage->setBaseAndMaxLevels(baseLevel, maxLevel);
...@@ -1198,14 +1238,13 @@ angle::Result TextureVk::changeLevels(ContextVk *contextVk, GLuint baseLevel, GL ...@@ -1198,14 +1238,13 @@ angle::Result TextureVk::changeLevels(ContextVk *contextVk, GLuint baseLevel, GL
uint32_t srcLevelVK = baseLevelChanged ? level - previousBaseLevel : level; uint32_t srcLevelVK = baseLevelChanged ? level - previousBaseLevel : level;
ASSERT(srcLevelVK <= mImage->getLevelCount()); ASSERT(srcLevelVK <= mImage->getLevelCount());
ANGLE_TRY( ANGLE_TRY(copyImageDataToStagingBuffer(contextVk, desc, true, layer, srcLevelVK, level,
copyImageDataToStagingBuffer(contextVk, desc, true, layer, srcLevelVK, level)); stagingBuffer));
} }
} }
// Inform the front end that we've updated the staging buffer // Inform the front end that we've updated the staging buffer
onStagingBufferChange(); onStagingBufferChange();
// Now that we've staged all the updates, release the current image so that it will be // Now that we've staged all the updates, release the current image so that it will be
// recreated with the correct number of mip levels, base level, and max level. // recreated with the correct number of mip levels, base level, and max level.
releaseImage(contextVk); releaseImage(contextVk);
...@@ -1326,17 +1365,39 @@ angle::Result TextureVk::syncState(const gl::Context *context, ...@@ -1326,17 +1365,39 @@ angle::Result TextureVk::syncState(const gl::Context *context,
{ {
ContextVk *contextVk = vk::GetImpl(context); ContextVk *contextVk = vk::GetImpl(context);
vk::BufferHelper *stagingBuffer = nullptr;
// Create a new image if the storage state is enabled for the first time.
if (dirtyBits.test(gl::Texture::DIRTY_BIT_BOUND_AS_IMAGE))
{
// Recreate the image to include storage bit if needed.
if (!(mImageUsageFlags & VK_IMAGE_USAGE_STORAGE_BIT))
{
mImageUsageFlags |= VK_IMAGE_USAGE_STORAGE_BIT;
ANGLE_TRY(changeLevels(contextVk, mImage->getBaseLevel(),
mState.getEffectiveBaseLevel(), mState.getEffectiveMaxLevel(),
&stagingBuffer));
}
}
// 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))
{ {
ANGLE_TRY( ANGLE_TRY(updateBaseMaxLevels(contextVk, mState.getEffectiveBaseLevel(),
changeLevels(contextVk, mState.getEffectiveBaseLevel(), mState.getEffectiveMaxLevel())); mState.getEffectiveMaxLevel(), &stagingBuffer));
} }
// Initialize the image storage and flush the pixel buffer. // Initialize the image storage and flush the pixel buffer.
ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels)); ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
if (stagingBuffer)
{
stagingBuffer->onRead(contextVk, mImage, VK_ACCESS_TRANSFER_READ_BIT);
// Different parts of the buffer might be read from or write to.
stagingBuffer->onSelfReadWrite(contextVk, VK_ACCESS_TRANSFER_READ_BIT,
VK_ACCESS_TRANSFER_WRITE_BIT);
}
if (dirtyBits.none() && mSampler.valid()) if (dirtyBits.none() && mSampler.valid())
{ {
return angle::Result::Continue; return angle::Result::Continue;
...@@ -1520,34 +1581,11 @@ angle::Result TextureVk::initImage(ContextVk *contextVk, ...@@ -1520,34 +1581,11 @@ angle::Result TextureVk::initImage(ContextVk *contextVk,
{ {
RendererVk *renderer = contextVk->getRenderer(); RendererVk *renderer = contextVk->getRenderer();
VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_TRANSFER_DST_BIT |
VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
VK_IMAGE_USAGE_SAMPLED_BIT;
// If the image has depth/stencil support, add those as possible usage.
if (renderer->hasImageFormatFeatureBits(format.vkImageFormat,
VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT))
{
imageUsageFlags |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
}
else if (renderer->hasImageFormatFeatureBits(format.vkImageFormat,
VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT))
{
imageUsageFlags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
}
// If the image has storage support, add it for ES3.1 image support.
if (renderer->hasImageFormatFeatureBits(format.vkImageFormat,
VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT))
{
imageUsageFlags |= VK_IMAGE_USAGE_STORAGE_BIT;
}
VkExtent3D vkExtent; VkExtent3D vkExtent;
uint32_t layerCount; uint32_t layerCount;
gl_vk::GetExtentsAndLayerCount(mState.getType(), extents, &vkExtent, &layerCount); gl_vk::GetExtentsAndLayerCount(mState.getType(), extents, &vkExtent, &layerCount);
ANGLE_TRY(mImage->init(contextVk, mState.getType(), vkExtent, format, 1, imageUsageFlags, ANGLE_TRY(mImage->init(contextVk, mState.getType(), vkExtent, format, 1, mImageUsageFlags,
mState.getEffectiveBaseLevel(), mState.getEffectiveMaxLevel(), mState.getEffectiveBaseLevel(), mState.getEffectiveMaxLevel(),
levelCount, layerCount)); levelCount, layerCount));
......
...@@ -322,7 +322,8 @@ class TextureVk : public TextureImpl ...@@ -322,7 +322,8 @@ class TextureVk : public TextureImpl
bool ignoreLayerCount, bool ignoreLayerCount,
uint32_t currentLayer, uint32_t currentLayer,
uint32_t sourceLevel, uint32_t sourceLevel,
uint32_t stagingDstMipLevel); uint32_t stagingDstMipLevel,
vk::BufferHelper **stagingBuffer);
angle::Result initImageViews(ContextVk *contextVk, angle::Result initImageViews(ContextVk *contextVk,
const vk::Format &format, const vk::Format &format,
const bool sized, const bool sized,
...@@ -341,9 +342,20 @@ class TextureVk : public TextureImpl ...@@ -341,9 +342,20 @@ class TextureVk : public TextureImpl
void onStagingBufferChange() { onStateChange(angle::SubjectMessage::SubjectChanged); } void onStagingBufferChange() { onStateChange(angle::SubjectMessage::SubjectChanged); }
angle::Result changeLevels(ContextVk *contextVk, GLuint baseLevel, GLuint maxLevel);
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.
angle::Result changeLevels(ContextVk *contextVk,
GLuint previousBaseLevel,
GLuint baseLevel,
GLuint maxLevel,
vk::BufferHelper **stagingBuffer);
// Update base and max levels, and re-create image if needed.
angle::Result updateBaseMaxLevels(ContextVk *contextVk,
GLuint baseLevel,
GLuint maxLevel,
vk::BufferHelper **stagingBuffer);
bool mOwnsImage; bool mOwnsImage;
...@@ -380,6 +392,9 @@ class TextureVk : public TextureImpl ...@@ -380,6 +392,9 @@ class TextureVk : public TextureImpl
// Overridden in some tests. // Overridden in some tests.
size_t mStagingBufferInitialSize; size_t mStagingBufferInitialSize;
// The created vkImage usage flag.
VkImageUsageFlags mImageUsageFlags;
}; };
} // namespace rx } // namespace rx
......
...@@ -574,6 +574,10 @@ ...@@ -574,6 +574,10 @@
// Fixed in later driver versions. // Fixed in later driver versions.
2727 VULKAN ANDROID : dEQP-GLES3.functional.shaders.builtin_variable.pointcoord = FAIL 2727 VULKAN ANDROID : dEQP-GLES3.functional.shaders.builtin_variable.pointcoord = FAIL
// New or broken formats in ES 3.0, may be it relates to VK_IMAGE_USAGE_STORAGE_BIT
3816 VULKAN PIXEL2ORXL : dEQP-GLES3.functional.texture.specification.texstorage3d.format.rgba16* = FAIL
3816 VULKAN PIXEL2ORXL : dEQP-GLES3.functional.texture.specification.texstorage3d.format.rgb16* = FAIL
3816 VULKAN PIXEL2ORXL : dEQP-GLES3.functional.texture.specification.texstorage3d.format.rg32* = FAIL
// Fails only with SwiftShader: // Fails only with SwiftShader:
......
...@@ -3508,6 +3508,117 @@ void main() ...@@ -3508,6 +3508,117 @@ void main()
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER); glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
} }
// Test that render pipeline and compute pipeline access to the same texture.
// Steps:
// 1. Clear the texture and DrawArrays.
// 2. DispatchCompute to set the image's first pixel to a specific color.
// 3. DrawArrays and check data.
TEST_P(ComputeShaderTest, DrawDispatchDrawPreserve)
{
const char kCSSource[] = R"(#version 310 es
layout(local_size_x=1, local_size_y=1) in;
layout(rgba8, binding = 0) writeonly uniform highp image2D image;
void main()
{
imageStore(image, ivec2(0, 0), vec4(0.0, 0.0, 1.0, 1.0));
})";
const char kVSSource[] = R"(#version 310 es
layout (location = 0) in vec2 pos;
in vec4 inTex;
out vec4 texCoord;
void main(void) {
texCoord = inTex;
gl_Position = vec4(pos, 0.0, 1.0);
})";
const char kFSSource[] = R"(#version 310 es
precision highp float;
uniform sampler2D tex;
in vec4 texCoord;
out vec4 fragColor;
void main(void) {
fragColor = texture(tex, texCoord.xy);
})";
GLuint aPosLoc = 0;
ANGLE_GL_PROGRAM(program, kVSSource, kFSSource);
glBindAttribLocation(program, aPosLoc, "pos");
unsigned char *data = new unsigned char[4 * getWindowWidth() * getWindowHeight()];
for (int i = 0; i < getWindowWidth() * getWindowHeight(); i++)
{
data[i * 4] = 0xff;
data[i * 4 + 1] = 0;
data[i * 4 + 2] = 0;
data[i * 4 + 3] = 0xff;
}
GLTexture texture;
glBindTexture(GL_TEXTURE_2D, texture);
glTexStorage2D(GL_TEXTURE_2D, 2, GL_RGBA8, getWindowWidth(), getWindowHeight());
// Clear the texture level 0 to Red.
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA,
GL_UNSIGNED_BYTE, data);
for (int i = 0; i < getWindowWidth() * getWindowHeight(); i++)
{
data[i * 4] = 0;
data[i * 4 + 1] = 0xff;
data[i * 4 + 2] = 0;
data[i * 4 + 3] = 0xff;
}
// Clear the texture level 1 to Green.
glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, getWindowWidth() / 2, getWindowHeight() / 2, GL_RGBA,
GL_UNSIGNED_BYTE, data);
delete[] data;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glUseProgram(program);
GLfloat vertices[] = {-1, -1, 1, -1, -1, 1, 1, 1};
GLfloat texCoords[] = {0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f};
GLint pos = glGetAttribLocation(program, "pos");
glEnableVertexAttribArray(pos);
glVertexAttribPointer(pos, 2, GL_FLOAT, GL_FALSE, 0, vertices);
GLint posTex = glGetAttribLocation(program, "inTex");
glEnableVertexAttribArray(posTex);
glVertexAttribPointer(posTex, 2, GL_FLOAT, GL_FALSE, 0, texCoords);
// Draw with level 0, the whole frame buffer should be Red.
glViewport(0, 0, getWindowWidth(), getWindowHeight());
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
EXPECT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - 1, getWindowHeight() - 1, GLColor::red);
// Draw with level 1, the whole frame buffer should be Green.
glViewport(0, 0, getWindowWidth() / 2, getWindowHeight() / 2);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2 - 1, getWindowHeight() / 2 - 1, GLColor::green);
// Clear the texture level 0's (0, 0) position to Blue.
glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA8);
ANGLE_GL_COMPUTE_PROGRAM(csProgram, kCSSource);
glUseProgram(csProgram);
glDispatchCompute(1, 1, 1);
glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT);
EXPECT_GL_NO_ERROR();
glFinish();
glUseProgram(program);
// Draw with level 0, the first position should be Blue.
glViewport(0, 0, getWindowWidth(), getWindowHeight());
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - 1, getWindowHeight() - 1, GLColor::red);
// Draw with level 1, the whole frame buffer should be Green.
glViewport(0, 0, getWindowWidth() / 2, getWindowHeight() / 2);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2 - 1, getWindowHeight() / 2 - 1, GLColor::green);
}
ANGLE_INSTANTIATE_TEST(ComputeShaderTest, ANGLE_INSTANTIATE_TEST(ComputeShaderTest,
ES31_OPENGL(), ES31_OPENGL(),
ES31_OPENGLES(), ES31_OPENGLES(),
......
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