Commit cc5f7989 by Mohan Maiya Committed by Commit Bot

Vulkan: Support gl_SampleMask with non-const index

Add support for access to gl_SampleMask or gl_SampleMaskIn with non-constant index. Replace gl_SampleMask with ANGLESampleMask and reassign ANGLESampleMask to gl_SampleMask in the end. Bug: angleproject:3588 Tests: dEQP-GLES31.functional.shaders.sample_variables.sample_mask. discard_half_per_pixel.* discard_half_per_sample.* Change-Id: Ie668c3ccf4d40352574db57f5e43b2f17ef6d8b8 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2477908 Commit-Queue: Mohan Maiya <m.maiya@samsung.com> Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org>
parent 8a401051
......@@ -237,6 +237,10 @@ angle_translator_sources = [
"src/compiler/translator/tree_util/ReplaceShadowingVariables.h",
"src/compiler/translator/tree_util/ReplaceVariable.cpp",
"src/compiler/translator/tree_util/ReplaceVariable.h",
"src/compiler/translator/tree_util/RewriteSampleMaskVariable.cpp",
"src/compiler/translator/tree_util/RewriteSampleMaskVariable.h",
"src/compiler/translator/tree_util/RunAtTheBeginningOfShader.cpp",
"src/compiler/translator/tree_util/RunAtTheBeginningOfShader.h",
"src/compiler/translator/tree_util/RunAtTheEndOfShader.cpp",
"src/compiler/translator/tree_util/RunAtTheEndOfShader.h",
"src/compiler/translator/tree_util/Visit.h",
......
......@@ -36,6 +36,7 @@
#include "compiler/translator/tree_util/IntermNode_util.h"
#include "compiler/translator/tree_util/ReplaceClipDistanceVariable.h"
#include "compiler/translator/tree_util/ReplaceVariable.h"
#include "compiler/translator/tree_util/RewriteSampleMaskVariable.h"
#include "compiler/translator/tree_util/RunAtTheEndOfShader.h"
#include "compiler/translator/util.h"
......@@ -811,8 +812,9 @@ bool TranslatorVulkan::translateImpl(TIntermBlock *root,
// if it's core profile shaders and they are used.
if (getShaderType() == GL_FRAGMENT_SHADER)
{
bool usesPointCoord = false;
bool usesFragCoord = false;
bool usesPointCoord = false;
bool usesFragCoord = false;
bool usesSampleMaskIn = false;
// Search for the gl_PointCoord usage, if its used, we need to flip the y coordinate.
for (const ShaderVariable &inputVarying : mInputVaryings)
......@@ -822,6 +824,12 @@ bool TranslatorVulkan::translateImpl(TIntermBlock *root,
continue;
}
if (inputVarying.name == "gl_SampleMaskIn")
{
usesSampleMaskIn = true;
continue;
}
if (inputVarying.name == "gl_PointCoord")
{
usesPointCoord = true;
......@@ -844,9 +852,10 @@ bool TranslatorVulkan::translateImpl(TIntermBlock *root,
}
}
bool hasGLFragColor = false;
bool hasGLFragData = false;
bool usePreRotation = compileOptions & SH_ADD_PRE_ROTATION;
bool hasGLFragColor = false;
bool hasGLFragData = false;
bool usePreRotation = compileOptions & SH_ADD_PRE_ROTATION;
bool hasGLSampleMask = false;
for (const ShaderVariable &outputVar : mOutputVariables)
{
......@@ -862,6 +871,12 @@ bool TranslatorVulkan::translateImpl(TIntermBlock *root,
hasGLFragData = true;
continue;
}
else if (outputVar.name == "gl_SampleMask")
{
ASSERT(!hasGLSampleMask);
hasGLSampleMask = true;
continue;
}
}
ASSERT(!(hasGLFragColor && hasGLFragData));
if (hasGLFragColor)
......@@ -921,6 +936,16 @@ bool TranslatorVulkan::translateImpl(TIntermBlock *root,
return false;
}
if (usesSampleMaskIn && !RewriteSampleMaskIn(this, root, &getSymbolTable()))
{
return false;
}
if (hasGLSampleMask && !RewriteSampleMask(this, root, &getSymbolTable()))
{
return false;
}
{
const TVariable *numSamplesVar = static_cast<const TVariable *>(
getSymbolTable().findBuiltIn(ImmutableString("gl_NumSamples"), getShaderVersion()));
......
//
// Copyright 2020 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// RewriteSampleMaskVariable.cpp: Find any references to gl_SampleMask and gl_SampleMaskIn, and
// rewrite it with ANGLESampleMask or ANGLESampleMaskIn.
//
#include "compiler/translator/tree_util/RewriteSampleMaskVariable.h"
#include "common/bitset_utils.h"
#include "common/debug.h"
#include "common/utilities.h"
#include "compiler/translator/SymbolTable.h"
#include "compiler/translator/tree_util/BuiltIn.h"
#include "compiler/translator/tree_util/IntermNode_util.h"
#include "compiler/translator/tree_util/IntermTraverse.h"
#include "compiler/translator/tree_util/RunAtTheBeginningOfShader.h"
#include "compiler/translator/tree_util/RunAtTheEndOfShader.h"
namespace sh
{
namespace
{
constexpr int kMaxIndexForSampleMaskVar = 0;
// Traverse the tree and collect the redeclaration and replace all non constant index references of
// gl_SampleMask or gl_SampleMaskIn with constant index references
class GLSampleMaskRelatedReferenceTraverser : public TIntermTraverser
{
public:
GLSampleMaskRelatedReferenceTraverser(const TIntermSymbol **redeclaredSymOut,
const ImmutableString &targetStr)
: TIntermTraverser(true, false, false),
mRedeclaredSym(redeclaredSymOut),
mTargetStr(targetStr)
{
*mRedeclaredSym = nullptr;
}
bool visitDeclaration(Visit visit, TIntermDeclaration *node) override
{
// If gl_SampleMask is redeclared, we need to collect its information
const TIntermSequence &sequence = *(node->getSequence());
if (sequence.size() != 1)
{
return true;
}
TIntermTyped *variable = sequence.front()->getAsTyped();
TIntermSymbol *symbol = variable->getAsSymbolNode();
if (symbol == nullptr || symbol->getName() != mTargetStr)
{
return true;
}
*mRedeclaredSym = symbol;
return true;
}
bool visitBinary(Visit visit, TIntermBinary *node) override
{
TOperator op = node->getOp();
if (op != EOpIndexDirect && op != EOpIndexIndirect)
{
return true;
}
TIntermSymbol *left = node->getLeft()->getAsSymbolNode();
if (!left)
{
return true;
}
if (left->getName() != mTargetStr)
{
return true;
}
const TConstantUnion *constIdx = node->getRight()->getConstantValue();
if (!constIdx)
{
if (node->getRight()->hasSideEffects())
{
insertStatementInParentBlock(node->getRight());
}
queueReplacementWithParent(node, node->getRight(),
CreateIndexNode(kMaxIndexForSampleMaskVar),
OriginalNode::IS_DROPPED);
}
return true;
}
private:
const TIntermSymbol **mRedeclaredSym;
const ImmutableString mTargetStr;
};
} // anonymous namespace
ANGLE_NO_DISCARD bool RewriteSampleMask(TCompiler *compiler,
TIntermBlock *root,
TSymbolTable *symbolTable)
{
const TIntermSymbol *redeclaredGLSampleMask = nullptr;
GLSampleMaskRelatedReferenceTraverser indexTraverser(&redeclaredGLSampleMask,
ImmutableString("gl_SampleMask"));
root->traverse(&indexTraverser);
if (!indexTraverser.updateTree(compiler, root))
{
return false;
}
// Retrieve gl_SampleMask variable reference
// Search user redeclared it first
const TVariable *glSampleMaskVar = nullptr;
if (redeclaredGLSampleMask)
{
glSampleMaskVar = &redeclaredGLSampleMask->variable();
}
else
{
// User defined not found, find in built-in table
glSampleMaskVar = static_cast<const TVariable *>(
symbolTable->findBuiltIn(ImmutableString("gl_SampleMask"), 320));
}
if (!glSampleMaskVar)
{
return false;
}
// Current ANGLE assumes that the maximum number of samples is less than or equal to
// VK_SAMPLE_COUNT_32_BIT. So, the size of gl_SampleMask array is always one.
const unsigned int arraySizeOfSampleMask = glSampleMaskVar->getType().getOutermostArraySize();
ASSERT(arraySizeOfSampleMask == 1);
return true;
}
ANGLE_NO_DISCARD bool RewriteSampleMaskIn(TCompiler *compiler,
TIntermBlock *root,
TSymbolTable *symbolTable)
{
const TIntermSymbol *redeclaredGLSampleMaskIn = nullptr;
GLSampleMaskRelatedReferenceTraverser indexTraverser(&redeclaredGLSampleMaskIn,
ImmutableString("gl_SampleMaskIn"));
root->traverse(&indexTraverser);
if (!indexTraverser.updateTree(compiler, root))
{
return false;
}
// Retrieve gl_SampleMaskIn variable reference
const TVariable *glSampleMaskInVar = nullptr;
glSampleMaskInVar = static_cast<const TVariable *>(
symbolTable->findBuiltIn(ImmutableString("gl_SampleMaskIn"), 320));
if (!glSampleMaskInVar)
{
return false;
}
// Current ANGLE assumes that the maximum number of samples is less than or equal to
// VK_SAMPLE_COUNT_32_BIT. So, the size of gl_SampleMask array is always one.
const unsigned int arraySizeOfSampleMaskIn =
glSampleMaskInVar->getType().getOutermostArraySize();
ASSERT(arraySizeOfSampleMaskIn == 1);
return true;
}
} // namespace sh
//
// Copyright 2020 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// RewriteSampleMaskVariable.cpp: Find any references to gl_SampleMask and gl_SampleMaskIn, and
// rewrite it with ANGLESampleMask or ANGLESampleMaskIn.
//
#ifndef COMPILER_TRANSLATOR_TREEUTIL_REWRITESAMPLEMASKVARIABLE_H_
#define COMPILER_TRANSLATOR_TREEUTIL_REWRITESAMPLEMASKVARIABLE_H_
#include "common/angleutils.h"
namespace sh
{
class TCompiler;
class TIntermBlock;
class TSymbolTable;
class TIntermTyped;
// Rewrite every gl_SampleMask or gl_SampleMaskIn to "ANGLESampleMask" or "ANGLESampleMaskIn", then
// at the end of shader re-assign the values of this global variable to gl_SampleMask and
// gl_SampleMaskIn. This to solve the problem which the non constant index is used for the unsized
// array problem.
ANGLE_NO_DISCARD bool RewriteSampleMask(TCompiler *compiler,
TIntermBlock *root,
TSymbolTable *symbolTable);
ANGLE_NO_DISCARD bool RewriteSampleMaskIn(TCompiler *compiler,
TIntermBlock *root,
TSymbolTable *symbolTable);
} // namespace sh
#endif // COMPILER_TRANSLATOR_TREEUTIL_REWRITESAMPLEMASKVARIABLE_H_
//
// Copyright 2020 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// RunAtTheBeginningOfShader.cpp: Add code to be run at the beginning of the shader.
// void main() { body }
// =>
// void main()
// {
// codeToRun
// body
// }
//
#include "compiler/translator/tree_util/RunAtTheBeginningOfShader.h"
#include "compiler/translator/Compiler.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/StaticType.h"
#include "compiler/translator/SymbolTable.h"
#include "compiler/translator/tree_util/FindMain.h"
#include "compiler/translator/tree_util/IntermNode_util.h"
#include "compiler/translator/tree_util/IntermTraverse.h"
namespace sh
{
bool RunAtTheBeginningOfShader(TCompiler *compiler, TIntermBlock *root, TIntermNode *codeToRun)
{
TIntermFunctionDefinition *main = FindMain(root);
main->getBody()->insertStatement(0, codeToRun);
return compiler->validateAST(root);
}
} // namespace sh
//
// Copyright 2020 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// RunAtTheBeginningOfShader.h: Add code to be run at the beginning of the shader.
//
#ifndef COMPILER_TRANSLATOR_TREEUTIL_RUNATTHEBEGINNINGOFSHADER_H_
#define COMPILER_TRANSLATOR_TREEUTIL_RUNATTHEBEGINNINGOFSHADER_H_
#include "common/angleutils.h"
namespace sh
{
class TCompiler;
class TIntermBlock;
class TIntermNode;
ANGLE_NO_DISCARD bool RunAtTheBeginningOfShader(TCompiler *compiler,
TIntermBlock *root,
TIntermNode *codeToRun);
} // namespace sh
#endif // COMPILER_TRANSLATOR_TREEUTIL_RUNATTHEBEGINNINGOFSHADER_H_
......@@ -80,6 +80,7 @@ angle_unittests_sources = [
"compiler_tests/InitOutputVariables_test.cpp",
"compiler_tests/IntermNode_test.cpp",
"compiler_tests/NV_draw_buffers_test.cpp",
"compiler_tests/OES_sample_variables_test.cpp",
"compiler_tests/OES_standard_derivatives_test.cpp",
"compiler_tests/OES_texture_cube_map_array_test.cpp",
"compiler_tests/OVR_multiview2_test.cpp",
......
//
// Copyright 2020 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// OES_sample_variables_test.cpp:
// Test for OES_sample_variables
//
#include "tests/test_utils/ShaderExtensionTest.h"
namespace
{
const char OESPragma[] = "#extension GL_OES_sample_variables : require\n";
// Shader using gl_SampleMask with non-constant index
// This shader is in the deqp test
// (functional_shaders_sample_variables_sample_mask_discard_half_per_sample_default_framebuffer)
const char ESSL310_GLSampleMaskShader[] =
R"(
layout(location = 0) out mediump vec4 fragColor;
void main (void)
{
for (int i = 0; i < gl_SampleMask.length(); ++i)
gl_SampleMask[i] = int(0xAAAAAAAA);
// force per-sample shading
highp float blue = float(gl_SampleID);
fragColor = vec4(0.0, 1.0, blue, 1.0);
})";
// Shader using gl_SampleMask with non-constant index
// This shader is based on the deqp test on below
// (functional_shaders_sample_variables_sample_mask_in_bit_count_per_sample_multisample_texture_2)
const char ESSL310_GLSampleMaskInShader[] =
R"(
layout(location = 0) out mediump vec4 fragColor;
void main (void)
{
mediump int maskBitCount = 0;
for (int j = 0; j < gl_SampleMaskIn.length(); ++j)
{
for (int i = 0; i < 32; ++i)
{
if (((gl_SampleMaskIn[j] >> i) & 0x01) == 0x01)
{
++maskBitCount;
}
}
}
// force per-sample shading
highp float blue = float(gl_SampleID);
if (maskBitCount != 1)
fragColor = vec4(1.0, 0.0, blue, 1.0);
else
fragColor = vec4(0.0, 1.0, blue, 1.0);
})";
class OESSampleVariablesTest : public sh::ShaderExtensionTest
{
public:
void InitializeCompiler() { InitializeCompiler(SH_GLSL_450_CORE_OUTPUT); }
void InitializeCompiler(ShShaderOutput shaderOutputType)
{
DestroyCompiler();
mCompiler = sh::ConstructCompiler(GL_FRAGMENT_SHADER, testing::get<0>(GetParam()),
shaderOutputType, &mResources);
ASSERT_TRUE(mCompiler != nullptr) << "Compiler could not be constructed.";
}
testing::AssertionResult TestShaderCompile(const char *pragma)
{
const char *shaderStrings[] = {testing::get<1>(GetParam()), pragma,
testing::get<2>(GetParam())};
bool success = sh::Compile(mCompiler, shaderStrings, 3, SH_VARIABLES | SH_OBJECT_CODE);
if (success)
{
return ::testing::AssertionSuccess() << "Compilation success";
}
return ::testing::AssertionFailure() << sh::GetInfoLog(mCompiler);
}
};
// GLES3 needs OES_sample_variables extension
class OESSampleVariablesTestES31 : public OESSampleVariablesTest
{};
// Extension flag is required to compile properly. Expect failure when it is
// not present.
TEST_P(OESSampleVariablesTestES31, CompileFailsWithoutExtension)
{
mResources.OES_sample_variables = 0;
InitializeCompiler();
EXPECT_FALSE(TestShaderCompile(OESPragma));
}
// Extension directive is required to compile properly. Expect failure when
// it is not present.
TEST_P(OESSampleVariablesTestES31, CompileFailsWithExtensionWithoutPragma)
{
mResources.OES_sample_variables = 1;
InitializeCompiler();
EXPECT_FALSE(TestShaderCompile(""));
}
// With extension flag and extension directive, compiling succeeds.
// Also test that the extension directive state is reset correctly.
#ifdef ANGLE_ENABLE_VULKAN
TEST_P(OESSampleVariablesTestES31, CompileSucceedsWithExtensionAndPragmaOnVulkan)
{
mResources.OES_sample_variables = 1;
InitializeCompiler(SH_GLSL_VULKAN_OUTPUT);
EXPECT_TRUE(TestShaderCompile(OESPragma));
// Test reset functionality.
EXPECT_FALSE(TestShaderCompile(""));
EXPECT_TRUE(TestShaderCompile(OESPragma));
}
#endif
INSTANTIATE_TEST_SUITE_P(CorrectESSL310Shaders,
OESSampleVariablesTestES31,
Combine(Values(SH_GLES3_1_SPEC),
Values(sh::ESSLVersion310),
Values(ESSL310_GLSampleMaskShader, ESSL310_GLSampleMaskInShader)));
} // anonymous namespace
......@@ -186,12 +186,6 @@
// Cannot create 2D (array) view of 3D texture.
3886 VULKAN : dEQP-GLES31.functional.image_load_store.3d.*layer = FAIL
// Cannot support a non-const indexing for gl_SampleMask or gl_SampleMaskIn variables:
3588 VULKAN : dEQP-GLES31.functional.shaders.sample_variables.sample_mask.discard_half_per_*.multisample_*_1 = FAIL
3588 VULKAN : dEQP-GLES31.functional.shaders.sample_variables.sample_mask.discard_half_per_*.multisample_*_2 = FAIL
3588 VULKAN : dEQP-GLES31.functional.shaders.sample_variables.sample_mask.discard_half_per_*.multisample_*_4 = FAIL
3588 VULKAN : dEQP-GLES31.functional.shaders.sample_variables.sample_mask.discard_half_per_*.multisample_*_8 = FAIL
// Cannot ignore multisampling-related operations when the target is a single-sampled target:
3588 VULKAN : dEQP-GLES31.functional.shaders.sample_variables.sample_mask.discard_half_per_*.default_framebuffer = FAIL
3588 VULKAN : dEQP-GLES31.functional.shaders.sample_variables.sample_mask.discard_half_per_*.singlesample_texture = FAIL
......
......@@ -66,11 +66,6 @@
// Incompatible between incomplete texture and sampler format (isampler2D or usampler2D):
3588 VULKAN : KHR-GLES31.core.sample_variables.mask.rgba8*i.* = SKIP
// Cannot support a non-const indexing for gl_SampleMask or gl_SampleMaskIn variables:
3588 VULKAN : KHR-GLES31.core.sample_variables.verification.extension = FAIL
3588 VULKAN : KHR-GLES31.core.sample_variables.mask.rgba8.samples_* = FAIL
3588 VULKAN : KHR-GLES31.core.sample_variables.mask.rgba32f.samples_* = FAIL
////
//// Desktop Vulkan expectations
////
......@@ -106,6 +101,10 @@
4159 VULKAN PIXEL2ORXL : KHR-GLES31.core.draw_indirect.advanced-twoPass-transformFeedback-elements = FAIL
4159 VULKAN PIXEL2ORXL : KHR-GLES31.core.draw_indirect.advanced-twoPass-transformFeedback-arrays = FAIL
// Fails to link the shader program on Pixel2 and Pixel2 XL
// These test are failed, but the fault about incomplete multisample texture, these tests need to be SKIP.
3588 VULKAN PIXEL2ORXL : KHR-GLES31.core.sample_variables.mask.rgba8.samples_*.mask_* = SKIP
// Android uses "old" sampler rewrite that doesn't support array of arrays
2703 VULKAN ANDROID : KHR-GLES31.core.arrays_of_arrays.* = SKIP
......
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