Commit 377e7487 by Xinyi He Committed by Commit Bot

Vulkan: Support array of array image type

Implement supporting the array of array of image type in uniform. Add a new end2end test for it. Bug: angleproject:3881 Change-Id: Idd757ae1d0ed34d585ae1ca5e0b6577459a0acb7 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2379335 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org>
parent b3a8f0bc
...@@ -343,6 +343,7 @@ class TType ...@@ -343,6 +343,7 @@ class TType
bool isSamplerCube() const { return type == EbtSamplerCube; } bool isSamplerCube() const { return type == EbtSamplerCube; }
bool isAtomicCounter() const { return IsAtomicCounter(type); } bool isAtomicCounter() const { return IsAtomicCounter(type); }
bool isSamplerVideoWEBGL() const { return type == EbtSamplerVideoWEBGL; } bool isSamplerVideoWEBGL() const { return type == EbtSamplerVideoWEBGL; }
bool isImage() const { return IsImage(type); }
private: private:
constexpr void invalidateMangledName() { mMangledName = nullptr; } constexpr void invalidateMangledName() { mMangledName = nullptr; }
......
...@@ -125,9 +125,9 @@ void TraverseArrayOfArraysVariable(const ShaderVariable &variable, ...@@ -125,9 +125,9 @@ void TraverseArrayOfArraysVariable(const ShaderVariable &variable,
} }
else else
{ {
if (gl::IsSamplerType(variable.type)) if (gl::IsSamplerType(variable.type) || gl::IsImageType(variable.type))
{ {
visitor->visitSampler(elementVar); visitor->visitSamplerOrImage(elementVar);
} }
else else
{ {
...@@ -455,24 +455,24 @@ std::string VariableNameVisitor::collapseMappedNameStack() const ...@@ -455,24 +455,24 @@ std::string VariableNameVisitor::collapseMappedNameStack() const
return CollapseNameStack(mMappedNameStack); return CollapseNameStack(mMappedNameStack);
} }
void VariableNameVisitor::visitSampler(const sh::ShaderVariable &sampler) void VariableNameVisitor::visitSamplerOrImage(const sh::ShaderVariable &variable)
{ {
if (!sampler.hasParentArrayIndex()) if (!variable.hasParentArrayIndex())
{ {
mNameStack.push_back(sampler.name); mNameStack.push_back(variable.name);
mMappedNameStack.push_back(sampler.mappedName); mMappedNameStack.push_back(variable.mappedName);
} }
std::string name = collapseNameStack(); std::string name = collapseNameStack();
std::string mappedName = collapseMappedNameStack(); std::string mappedName = collapseMappedNameStack();
if (!sampler.hasParentArrayIndex()) if (!variable.hasParentArrayIndex())
{ {
mNameStack.pop_back(); mNameStack.pop_back();
mMappedNameStack.pop_back(); mMappedNameStack.pop_back();
} }
visitNamedSampler(sampler, name, mappedName, mArraySizeStack); visitNamedSamplerOrImage(variable, name, mappedName, mArraySizeStack);
} }
void VariableNameVisitor::visitVariable(const ShaderVariable &variable, bool isRowMajor) void VariableNameVisitor::visitVariable(const ShaderVariable &variable, bool isRowMajor)
...@@ -610,9 +610,9 @@ void TraverseShaderVariable(const ShaderVariable &variable, ...@@ -610,9 +610,9 @@ void TraverseShaderVariable(const ShaderVariable &variable,
{ {
TraverseArrayOfArraysVariable(variable, 0u, isRowMajor, visitor); TraverseArrayOfArraysVariable(variable, 0u, isRowMajor, visitor);
} }
else if (gl::IsSamplerType(variable.type)) else if (gl::IsSamplerType(variable.type) || gl::IsImageType(variable.type))
{ {
visitor->visitSampler(variable); visitor->visitSamplerOrImage(variable);
} }
else else
{ {
......
...@@ -201,7 +201,7 @@ class ShaderVariableVisitor ...@@ -201,7 +201,7 @@ class ShaderVariableVisitor
virtual void enterArrayElement(const ShaderVariable &arrayVar, unsigned int arrayElement) {} virtual void enterArrayElement(const ShaderVariable &arrayVar, unsigned int arrayElement) {}
virtual void exitArrayElement(const ShaderVariable &arrayVar, unsigned int arrayElement) {} virtual void exitArrayElement(const ShaderVariable &arrayVar, unsigned int arrayElement) {}
virtual void visitSampler(const sh::ShaderVariable &sampler) {} virtual void visitSamplerOrImage(const sh::ShaderVariable &variable) {}
virtual void visitVariable(const ShaderVariable &variable, bool isRowMajor) = 0; virtual void visitVariable(const ShaderVariable &variable, bool isRowMajor) = 0;
...@@ -225,10 +225,10 @@ class VariableNameVisitor : public ShaderVariableVisitor ...@@ -225,10 +225,10 @@ class VariableNameVisitor : public ShaderVariableVisitor
void exitArrayElement(const ShaderVariable &arrayVar, unsigned int arrayElement) override; void exitArrayElement(const ShaderVariable &arrayVar, unsigned int arrayElement) override;
protected: protected:
virtual void visitNamedSampler(const sh::ShaderVariable &sampler, virtual void visitNamedSamplerOrImage(const sh::ShaderVariable &sampler,
const std::string &name, const std::string &name,
const std::string &mappedName, const std::string &mappedName,
const std::vector<unsigned int> &arraySizes) const std::vector<unsigned int> &arraySizes)
{} {}
virtual void visitNamedVariable(const ShaderVariable &variable, virtual void visitNamedVariable(const ShaderVariable &variable,
bool isRowMajor, bool isRowMajor,
...@@ -240,7 +240,7 @@ class VariableNameVisitor : public ShaderVariableVisitor ...@@ -240,7 +240,7 @@ class VariableNameVisitor : public ShaderVariableVisitor
std::string collapseMappedNameStack() const; std::string collapseMappedNameStack() const;
private: private:
void visitSampler(const sh::ShaderVariable &sampler) final; void visitSamplerOrImage(const sh::ShaderVariable &variable) final;
void visitVariable(const ShaderVariable &variable, bool isRowMajor) final; void visitVariable(const ShaderVariable &variable, bool isRowMajor) final;
std::vector<std::string> mNameStack; std::vector<std::string> mNameStack;
......
...@@ -353,7 +353,7 @@ class Traverser final : public TIntermTraverser, public ArrayTraverser ...@@ -353,7 +353,7 @@ class Traverser final : public TIntermTraverser, public ArrayTraverser
mMultiReplacements.emplace_back(getParentNode()->getAsBlock(), decl, *newSequence); mMultiReplacements.emplace_back(getParentNode()->getAsBlock(), decl, *newSequence);
} }
if (type.isSampler() && type.isArray()) if ((type.isSampler() || type.isImage()) && type.isArray())
{ {
TIntermSequence *newSequence = new TIntermSequence; TIntermSequence *newSequence = new TIntermSequence;
TIntermSymbol *asSymbol = declarator->getAsSymbolNode(); TIntermSymbol *asSymbol = declarator->getAsSymbolNode();
...@@ -373,9 +373,10 @@ class Traverser final : public TIntermTraverser, public ArrayTraverser ...@@ -373,9 +373,10 @@ class Traverser final : public TIntermTraverser, public ArrayTraverser
{ {
if (visit != PreVisit) if (visit != PreVisit)
return true; return true;
// If the node isn't a sampler or if this isn't the outermost access, // If the node isn't a sampler and it isn't an image or if this isn't the outermost
// continue. // access, continue.
if (!node->getType().isSampler() || node->getType().isArray()) if ((!node->getType().isSampler() && !node->getType().isImage()) ||
node->getType().isArray())
{ {
return true; return true;
} }
......
...@@ -3705,6 +3705,9 @@ void Program::linkSamplerAndImageBindings(GLuint *combinedImageUniforms) ...@@ -3705,6 +3705,9 @@ void Program::linkSamplerAndImageBindings(GLuint *combinedImageUniforms)
std::vector<ImageBinding> &imageBindings = hasComputeShader std::vector<ImageBinding> &imageBindings = hasComputeShader
? mState.mExecutable->mComputeImageBindings ? mState.mExecutable->mComputeImageBindings
: mState.mExecutable->mGraphicsImageBindings; : mState.mExecutable->mGraphicsImageBindings;
// The arrays of arrays are flattened to arrays, it needs to record the array offset for the
// correct binding image unit.
uint32_t arrayOffset = 0;
// If uniform is a image type, insert it into the mImageBindings array. // If uniform is a image type, insert it into the mImageBindings array.
for (unsigned int imageIndex : mState.mExecutable->getImageUniformRange()) for (unsigned int imageIndex : mState.mExecutable->getImageUniformRange())
{ {
...@@ -3719,12 +3722,21 @@ void Program::linkSamplerAndImageBindings(GLuint *combinedImageUniforms) ...@@ -3719,12 +3722,21 @@ void Program::linkSamplerAndImageBindings(GLuint *combinedImageUniforms)
} }
else else
{ {
imageBindings.emplace_back( imageBindings.emplace_back(ImageBinding(imageUniform.binding + arrayOffset,
ImageBinding(imageUniform.binding, imageUniform.getBasicTypeElementCount(), false)); imageUniform.getBasicTypeElementCount(),
false));
} }
GLuint arraySize = imageUniform.isArray() ? imageUniform.arraySizes[0] : 1u; GLuint arraySize = imageUniform.isArray() ? imageUniform.arraySizes[0] : 1u;
*combinedImageUniforms += imageUniform.activeShaderCount() * arraySize; *combinedImageUniforms += imageUniform.activeShaderCount() * arraySize;
if (imageUniform.hasParentArrayIndex() && imageUniform.isArray())
{
arrayOffset += arraySize;
}
else
{
arrayOffset = 0;
}
} }
highIter = lowIter; highIter = lowIter;
......
...@@ -397,10 +397,10 @@ class FlattenUniformVisitor : public sh::VariableNameVisitor ...@@ -397,10 +397,10 @@ class FlattenUniformVisitor : public sh::VariableNameVisitor
mUnusedUniforms(unusedUniforms) mUnusedUniforms(unusedUniforms)
{} {}
void visitNamedSampler(const sh::ShaderVariable &sampler, void visitNamedSamplerOrImage(const sh::ShaderVariable &sampler,
const std::string &name, const std::string &name,
const std::string &mappedName, const std::string &mappedName,
const std::vector<unsigned int> &arraySizes) override const std::vector<unsigned int> &arraySizes) override
{ {
visitNamedVariable(sampler, false, name, mappedName, arraySizes); visitNamedVariable(sampler, false, name, mappedName, arraySizes);
} }
......
...@@ -222,10 +222,10 @@ class UniformEncodingVisitorD3D : public sh::BlockEncoderVisitor ...@@ -222,10 +222,10 @@ class UniformEncodingVisitorD3D : public sh::BlockEncoderVisitor
mUniformMapOut(uniformMapOut) mUniformMapOut(uniformMapOut)
{} {}
void visitNamedSampler(const sh::ShaderVariable &sampler, void visitNamedSamplerOrImage(const sh::ShaderVariable &sampler,
const std::string &name, const std::string &name,
const std::string &mappedName, const std::string &mappedName,
const std::vector<unsigned int> &arraySizes) override const std::vector<unsigned int> &arraySizes) override
{ {
auto uniformMapEntry = mUniformMapOut->find(name); auto uniformMapEntry = mUniformMapOut->find(name);
if (uniformMapEntry == mUniformMapOut->end()) if (uniformMapEntry == mUniformMapOut->end())
......
...@@ -450,6 +450,7 @@ void ProgramExecutableVk::addAtomicCounterBufferDescriptorSetDesc( ...@@ -450,6 +450,7 @@ void ProgramExecutableVk::addAtomicCounterBufferDescriptorSetDesc(
} }
void ProgramExecutableVk::addImageDescriptorSetDesc(const gl::ProgramExecutable &executable, void ProgramExecutableVk::addImageDescriptorSetDesc(const gl::ProgramExecutable &executable,
bool useOldRewriteStructSamplers,
vk::DescriptorSetLayoutDesc *descOut) vk::DescriptorSetLayoutDesc *descOut)
{ {
const std::vector<gl::ImageBinding> &imageBindings = executable.getImageBindings(); const std::vector<gl::ImageBinding> &imageBindings = executable.getImageBindings();
...@@ -461,9 +462,29 @@ void ProgramExecutableVk::addImageDescriptorSetDesc(const gl::ProgramExecutable ...@@ -461,9 +462,29 @@ void ProgramExecutableVk::addImageDescriptorSetDesc(const gl::ProgramExecutable
uint32_t uniformIndex = executable.getUniformIndexFromImageIndex(imageIndex); uint32_t uniformIndex = executable.getUniformIndexFromImageIndex(imageIndex);
const gl::LinkedUniform &imageUniform = uniforms[uniformIndex]; const gl::LinkedUniform &imageUniform = uniforms[uniformIndex];
std::string imageName = useOldRewriteStructSamplers
? GetMappedSamplerNameOld(imageUniform.name)
: GlslangGetMappedSamplerName(imageUniform.name);
// The front-end always binds array image units sequentially. // The front-end always binds array image units sequentially.
uint32_t arraySize = static_cast<uint32_t>(imageBinding.boundImageUnits.size()); uint32_t arraySize = static_cast<uint32_t>(imageBinding.boundImageUnits.size());
if (!useOldRewriteStructSamplers)
{
// 2D arrays are split into multiple 1D arrays when generating
// LinkedUniforms. Since they are flattened into one array, ignore the
// nonzero elements and expand the array to the total array size.
if (gl::SamplerNameContainsNonZeroArrayElement(imageUniform.name))
{
continue;
}
for (unsigned int outerArraySize : imageUniform.outerArraySizes)
{
arraySize *= outerArraySize;
}
}
for (const gl::ShaderType shaderType : executable.getLinkedShaderStages()) for (const gl::ShaderType shaderType : executable.getLinkedShaderStages())
{ {
if (!imageUniform.isActive(shaderType)) if (!imageUniform.isActive(shaderType))
...@@ -471,9 +492,8 @@ void ProgramExecutableVk::addImageDescriptorSetDesc(const gl::ProgramExecutable ...@@ -471,9 +492,8 @@ void ProgramExecutableVk::addImageDescriptorSetDesc(const gl::ProgramExecutable
continue; continue;
} }
std::string name = imageUniform.mappedName; GetImageNameWithoutIndices(&imageName);
GetImageNameWithoutIndices(&name); ShaderInterfaceVariableInfo &info = mVariableInfoMap[shaderType][imageName];
ShaderInterfaceVariableInfo &info = mVariableInfoMap[shaderType][name];
VkShaderStageFlags activeStages = gl_vk::kShaderStageMap[shaderType]; VkShaderStageFlags activeStages = gl_vk::kShaderStageMap[shaderType];
descOut->update(info.binding, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, arraySize, activeStages, descOut->update(info.binding, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, arraySize, activeStages,
nullptr); nullptr);
...@@ -736,7 +756,8 @@ angle::Result ProgramExecutableVk::updatePipelineLayout( ...@@ -736,7 +756,8 @@ angle::Result ProgramExecutableVk::updatePipelineLayout(
{ {
const gl::ProgramState *programState = programStates[shaderType]; const gl::ProgramState *programState = programStates[shaderType];
ASSERT(programState); ASSERT(programState);
addImageDescriptorSetDesc(programState->getExecutable(), &resourcesSetDesc); addImageDescriptorSetDesc(programState->getExecutable(),
contextVk->useOldRewriteStructSamplers(), &resourcesSetDesc);
} }
ANGLE_TRY(renderer->getDescriptorSetLayout( ANGLE_TRY(renderer->getDescriptorSetLayout(
...@@ -1146,6 +1167,9 @@ angle::Result ProgramExecutableVk::updateImagesDescriptorSet( ...@@ -1146,6 +1167,9 @@ angle::Result ProgramExecutableVk::updateImagesDescriptorSet(
const gl::ActiveTextureArray<TextureVk *> &activeImages = contextVk->getActiveImages(); const gl::ActiveTextureArray<TextureVk *> &activeImages = contextVk->getActiveImages();
bool useOldRewriteStructSamplers = contextVk->useOldRewriteStructSamplers();
std::unordered_map<std::string, uint32_t> mappedImageNameToArrayOffset;
// Write images. // Write images.
for (uint32_t imageIndex = 0; imageIndex < imageBindings.size(); ++imageIndex) for (uint32_t imageIndex = 0; imageIndex < imageBindings.size(); ++imageIndex)
{ {
...@@ -1158,14 +1182,34 @@ angle::Result ProgramExecutableVk::updateImagesDescriptorSet( ...@@ -1158,14 +1182,34 @@ angle::Result ProgramExecutableVk::updateImagesDescriptorSet(
continue; continue;
} }
std::string name = imageUniform.mappedName; std::string mappedImageName;
GetImageNameWithoutIndices(&name); if (!useOldRewriteStructSamplers)
ShaderInterfaceVariableInfo &info = mVariableInfoMap[shaderType][name]; {
mappedImageName = GlslangGetMappedSamplerName(imageUniform.mappedName);
}
else
{
mappedImageName = imageUniform.mappedName;
}
GetImageNameWithoutIndices(&mappedImageName);
ASSERT(!imageBinding.unreferenced); ASSERT(!imageBinding.unreferenced);
for (uint32_t arrayElement = 0; arrayElement < imageBinding.boundImageUnits.size(); uint32_t arrayOffset = 0;
++arrayElement) uint32_t arraySize = static_cast<uint32_t>(imageBinding.boundImageUnits.size());
if (!useOldRewriteStructSamplers)
{
arrayOffset = mappedImageNameToArrayOffset[mappedImageName];
// Front-end generates array elements in order, so we can just increment
// the offset each time we process a nested array.
mappedImageNameToArrayOffset[mappedImageName] += arraySize;
}
VkDescriptorImageInfo *imageInfos = contextVk->allocDescriptorImageInfos(arraySize);
VkWriteDescriptorSet *writeInfos = contextVk->allocWriteDescriptorSets(arraySize);
for (uint32_t arrayElement = 0; arrayElement < arraySize; ++arrayElement)
{ {
GLuint imageUnit = imageBinding.boundImageUnits[arrayElement]; GLuint imageUnit = imageBinding.boundImageUnits[arrayElement];
const gl::ImageUnit &binding = glState.getImageUnit(imageUnit); const gl::ImageUnit &binding = glState.getImageUnit(imageUnit);
...@@ -1181,23 +1225,26 @@ angle::Result ProgramExecutableVk::updateImagesDescriptorSet( ...@@ -1181,23 +1225,26 @@ angle::Result ProgramExecutableVk::updateImagesDescriptorSet(
// TODO(syoussefi): Support image data reinterpretation by using binding.format. // TODO(syoussefi): Support image data reinterpretation by using binding.format.
// http://anglebug.com/3563 // http://anglebug.com/3563
VkDescriptorImageInfo &imageInfo = contextVk->allocDescriptorImageInfo(); imageInfos[arrayElement].sampler = VK_NULL_HANDLE;
VkWriteDescriptorSet &writeInfo = contextVk->allocWriteDescriptorSet(); imageInfos[arrayElement].imageView = imageView->getHandle();
imageInfos[arrayElement].imageLayout = image->getCurrentLayout();
imageInfo.sampler = VK_NULL_HANDLE;
imageInfo.imageView = imageView->getHandle(); ShaderInterfaceVariableInfoMap &variableInfoMap = mVariableInfoMap[shaderType];
imageInfo.imageLayout = image->getCurrentLayout(); const std::string imageName = useOldRewriteStructSamplers
? GetMappedSamplerNameOld(imageUniform.name)
writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; : GlslangGetMappedSamplerName(imageUniform.name);
writeInfo.pNext = nullptr; ShaderInterfaceVariableInfo &info = variableInfoMap[imageName];
writeInfo.dstSet = descriptorSet;
writeInfo.dstBinding = info.binding; writeInfos[arrayElement].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writeInfo.dstArrayElement = arrayElement; writeInfos[arrayElement].pNext = nullptr;
writeInfo.descriptorCount = 1; writeInfos[arrayElement].dstSet = descriptorSet;
writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; writeInfos[arrayElement].dstBinding = info.binding;
writeInfo.pImageInfo = &imageInfo; writeInfos[arrayElement].dstArrayElement = arrayOffset + arrayElement;
writeInfo.pBufferInfo = nullptr; writeInfos[arrayElement].descriptorCount = 1;
writeInfo.pTexelBufferView = nullptr; writeInfos[arrayElement].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
writeInfos[arrayElement].pImageInfo = &imageInfos[arrayElement];
writeInfos[arrayElement].pBufferInfo = nullptr;
writeInfos[arrayElement].pTexelBufferView = nullptr;
} }
} }
......
...@@ -191,6 +191,7 @@ class ProgramExecutableVk ...@@ -191,6 +191,7 @@ class ProgramExecutableVk
const gl::ShaderType shaderType, const gl::ShaderType shaderType,
vk::DescriptorSetLayoutDesc *descOut); vk::DescriptorSetLayoutDesc *descOut);
void addImageDescriptorSetDesc(const gl::ProgramExecutable &executable, void addImageDescriptorSetDesc(const gl::ProgramExecutable &executable,
bool useOldRewriteStructSamplers,
vk::DescriptorSetLayoutDesc *descOut); vk::DescriptorSetLayoutDesc *descOut);
void addTextureDescriptorSetDesc(const gl::ProgramState &programState, void addTextureDescriptorSetDesc(const gl::ProgramState &programState,
bool useOldRewriteStructSamplers, bool useOldRewriteStructSamplers,
......
...@@ -163,9 +163,9 @@ ...@@ -163,9 +163,9 @@
// Not failing in last official run, but failed recently: // Not failing in last official run, but failed recently:
4110 SWIFTSHADER : dEQP-GLES31.functional.shaders.helper_invocation.* = FAIL 4110 SWIFTSHADER : dEQP-GLES31.functional.shaders.helper_invocation.* = FAIL
// Vulkan doesn't support array of array of opaque uniforms. Emulation is not yet done for images // Vulkan Android doesn't support array of array of opaque uniforms. Emulation is not yet done for images
3881 VULKAN : dEQP-GLES31.functional.program_interface_query.uniform.location.default_block.array.array.image_2d = SKIP 3881 VULKAN ANDROID : dEQP-GLES31.functional.program_interface_query.uniform.location.default_block.array.array.image_2d = SKIP
3881 VULKAN : dEQP-GLES31.functional.program_interface_query.uniform.location.default_block.array.array.iimage_2d_array = SKIP 3881 VULKAN ANDROID : dEQP-GLES31.functional.program_interface_query.uniform.location.default_block.array.array.iimage_2d_array = SKIP
// Flaky crashes in Windows x86 Subzero Reactor // Flaky crashes in Windows x86 Subzero Reactor
4482 WIN SWIFTSHADER : dEQP-GLES31.functional.synchronization.inter_invocation.* = SKIP 4482 WIN SWIFTSHADER : dEQP-GLES31.functional.synchronization.inter_invocation.* = SKIP
......
...@@ -3421,6 +3421,86 @@ TEST_P(GLSLTest_ES31, ArraysOfArraysSampler) ...@@ -3421,6 +3421,86 @@ TEST_P(GLSLTest_ES31, ArraysOfArraysSampler)
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
} }
// Test that arrays of arrays of images work as expected.
TEST_P(GLSLTest_ES31, ArraysOfArraysImage)
{
// anglebug.com/2703 - QC doesn't support arrays of image as parameters,
// so image array of array handling is disabled
ANGLE_SKIP_TEST_IF(IsAndroid() && IsVulkan());
// Fails on D3D due to mistranslation.
ANGLE_SKIP_TEST_IF(IsD3D());
// Fails on Android on GLES.
ANGLE_SKIP_TEST_IF(IsAndroid() && IsOpenGLES());
GLint maxTextures, maxComputeImageUniforms;
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextures);
glGetIntegerv(GL_MAX_COMPUTE_IMAGE_UNIFORMS, &maxComputeImageUniforms);
ANGLE_SKIP_TEST_IF(maxTextures < 1 * 2 * 3);
ANGLE_SKIP_TEST_IF(maxComputeImageUniforms < 1 * 2 * 3);
constexpr char kComputeShader[] = R"(#version 310 es
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout(binding = 0, r32ui) uniform highp readonly uimage2D image[1][2][3];
layout(binding = 1, std430) buffer Output {
uint image_value;
} outbuf;
void main(void)
{
outbuf.image_value = uint(0.0);
outbuf.image_value += imageLoad(image[0][0][0], ivec2(0, 0)).x;
outbuf.image_value += imageLoad(image[0][0][1], ivec2(0, 0)).x;
outbuf.image_value += imageLoad(image[0][0][2], ivec2(0, 0)).x;
outbuf.image_value += imageLoad(image[0][1][0], ivec2(0, 0)).x;
outbuf.image_value += imageLoad(image[0][1][1], ivec2(0, 0)).x;
outbuf.image_value += imageLoad(image[0][1][2], ivec2(0, 0)).x;
})";
ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShader);
EXPECT_GL_NO_ERROR();
glUseProgram(program);
GLuint outputInitData[1] = {10};
GLBuffer outputBuffer;
glBindBuffer(GL_SHADER_STORAGE_BUFFER, outputBuffer);
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(outputInitData), outputInitData, GL_STATIC_DRAW);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, outputBuffer);
EXPECT_GL_NO_ERROR();
GLuint imageData = 200u;
GLTexture images[1][2][3];
for (int i = 0; i < 1; i++)
{
for (int j = 0; j < 2; j++)
{
for (int k = 0; k < 3; k++)
{
glBindTexture(GL_TEXTURE_2D, images[i][j][k]);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, 1, 1);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RED_INTEGER, GL_UNSIGNED_INT,
&imageData);
glBindImageTexture(i * 6 + j * 3 + k, images[i][j][k], 0, GL_FALSE, 0, GL_READ_ONLY,
GL_R32UI);
EXPECT_GL_NO_ERROR();
}
}
}
glDispatchCompute(1, 1, 1);
EXPECT_GL_NO_ERROR();
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
// read back
const GLuint *ptr = reinterpret_cast<const GLuint *>(
glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(outputInitData), GL_MAP_READ_BIT));
memcpy(outputInitData, ptr, sizeof(outputInitData));
EXPECT_EQ(outputInitData[0], imageData * 1 * 2 * 3);
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
}
// Test that structs containing arrays of samplers work as expected. // Test that structs containing arrays of samplers work as expected.
TEST_P(GLSLTest_ES31, StructArraySampler) TEST_P(GLSLTest_ES31, StructArraySampler)
{ {
......
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