Commit 34130c2e by Mohan Maiya Committed by Commit Bot

Vulkan: Rewrite interpolateAtOffset to account for Y-flip

In order to fully suppot OES_shader_multisample_interpolation rewrite interpolateAtOffset's offset parameter to account for Y-coordinate flip. Bug: angleproject:3589 Tests: dEQP-GLES31.functional.shaders.multisample_interpolation. interpolate_at_offset.*.default_framebuffer Change-Id: I6bf72ceb1c0466ff5d4a92b72d1ec9e2552d6f2a Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2524711 Commit-Queue: Mohan Maiya <m.maiya@samsung.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org>
parent 06eaaac5
...@@ -178,6 +178,8 @@ angle_translator_sources = [ ...@@ -178,6 +178,8 @@ angle_translator_sources = [
"src/compiler/translator/tree_ops/RewriteDoWhile.h", "src/compiler/translator/tree_ops/RewriteDoWhile.h",
"src/compiler/translator/tree_ops/RewriteExpressionsWithShaderStorageBlock.cpp", "src/compiler/translator/tree_ops/RewriteExpressionsWithShaderStorageBlock.cpp",
"src/compiler/translator/tree_ops/RewriteExpressionsWithShaderStorageBlock.h", "src/compiler/translator/tree_ops/RewriteExpressionsWithShaderStorageBlock.h",
"src/compiler/translator/tree_ops/RewriteInterpolateAtOffset.cpp",
"src/compiler/translator/tree_ops/RewriteInterpolateAtOffset.h",
"src/compiler/translator/tree_ops/RewriteRepeatedAssignToSwizzled.cpp", "src/compiler/translator/tree_ops/RewriteRepeatedAssignToSwizzled.cpp",
"src/compiler/translator/tree_ops/RewriteRepeatedAssignToSwizzled.h", "src/compiler/translator/tree_ops/RewriteRepeatedAssignToSwizzled.h",
"src/compiler/translator/tree_ops/RewriteRowMajorMatrices.cpp", "src/compiler/translator/tree_ops/RewriteRowMajorMatrices.cpp",
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "compiler/translator/tree_ops/RewriteAtomicCounters.h" #include "compiler/translator/tree_ops/RewriteAtomicCounters.h"
#include "compiler/translator/tree_ops/RewriteCubeMapSamplersAs2DArray.h" #include "compiler/translator/tree_ops/RewriteCubeMapSamplersAs2DArray.h"
#include "compiler/translator/tree_ops/RewriteDfdy.h" #include "compiler/translator/tree_ops/RewriteDfdy.h"
#include "compiler/translator/tree_ops/RewriteInterpolateAtOffset.h"
#include "compiler/translator/tree_ops/RewriteStructSamplers.h" #include "compiler/translator/tree_ops/RewriteStructSamplers.h"
#include "compiler/translator/tree_util/BuiltIn.h" #include "compiler/translator/tree_util/BuiltIn.h"
#include "compiler/translator/tree_util/FindFunction.h" #include "compiler/translator/tree_util/FindFunction.h"
...@@ -1022,6 +1023,17 @@ bool TranslatorVulkan::translateImpl(TIntermBlock *root, ...@@ -1022,6 +1023,17 @@ bool TranslatorVulkan::translateImpl(TIntermBlock *root,
} }
} }
{
TIntermBinary *flipXY = CreateDriverUniformRef(driverUniforms, kFlipXY);
TIntermBinary *fragRotation =
usePreRotation ? CreateDriverUniformRef(driverUniforms, kFragRotation) : nullptr;
if (!RewriteInterpolateAtOffset(this, root, getSymbolTable(), getShaderVersion(),
flipXY, fragRotation))
{
return false;
}
}
EmitEarlyFragmentTestsGLSL(*this, sink); EmitEarlyFragmentTestsGLSL(*this, sink);
} }
else if (getShaderType() == GL_VERTEX_SHADER) else if (getShaderType() == GL_VERTEX_SHADER)
......
//
// 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.
//
// Implementation of InterpolateAtOffset viewport transformation.
// See header for more info.
#include "compiler/translator/tree_ops/RewriteDfdy.h"
#include "common/angleutils.h"
#include "compiler/translator/StaticType.h"
#include "compiler/translator/SymbolTable.h"
#include "compiler/translator/tree_util/IntermNode_util.h"
#include "compiler/translator/tree_util/IntermTraverse.h"
namespace sh
{
namespace
{
class Traverser : public TIntermTraverser
{
public:
ANGLE_NO_DISCARD static bool Apply(TCompiler *compiler,
TIntermNode *root,
const TSymbolTable &symbolTable,
TIntermBinary *flipXY,
TIntermTyped *fragRotation,
int ShaderVersion);
private:
Traverser(TIntermBinary *flipXY,
TIntermTyped *fragRotation,
TSymbolTable *symbolTable,
int shaderVersion);
bool visitAggregate(Visit visit, TIntermAggregate *node) override;
TIntermBinary *mFlipXY = nullptr;
TIntermTyped *mFragRotation = nullptr;
const TSymbolTable *symbolTable = nullptr;
const int shaderVersion;
};
Traverser::Traverser(TIntermBinary *flipXY,
TIntermTyped *fragRotation,
TSymbolTable *symbolTable,
int shaderVersion)
: TIntermTraverser(true, false, false, symbolTable),
mFlipXY(flipXY),
mFragRotation(fragRotation),
symbolTable(symbolTable),
shaderVersion(shaderVersion)
{}
// static
bool Traverser::Apply(TCompiler *compiler,
TIntermNode *root,
const TSymbolTable &symbolTable,
TIntermBinary *flipXY,
TIntermTyped *fragRotation,
int shaderVersion)
{
TSymbolTable *pSymbolTable = const_cast<TSymbolTable *>(&symbolTable);
Traverser traverser(flipXY, fragRotation, pSymbolTable, shaderVersion);
root->traverse(&traverser);
return traverser.updateTree(compiler, root);
}
bool Traverser::visitAggregate(Visit visit, TIntermAggregate *node)
{
// Decide if the node represents the call of texelFetchOffset.
if (node->getOp() != EOpCallBuiltInFunction)
{
return true;
}
ASSERT(node->getFunction()->symbolType() == SymbolType::BuiltIn);
if (node->getFunction()->name() != "interpolateAtOffset")
{
return true;
}
const TIntermSequence *sequence = node->getSequence();
ASSERT(sequence->size() == 2u);
TIntermSequence *interpolateAtOffsetArguments = new TIntermSequence();
// interpolant node
interpolateAtOffsetArguments->push_back(sequence->at(0));
// offset
TIntermTyped *offsetNode = sequence->at(1)->getAsTyped();
ASSERT(offsetNode->getType() == *(StaticType::GetBasic<EbtFloat, 2>()));
// If pre-rotation is enabled apply the transformation else just flip the Y-coordinate
TIntermTyped *rotatedXY;
if (mFragRotation)
{
rotatedXY =
new TIntermBinary(EOpMatrixTimesVector, mFragRotation->deepCopy(), mFlipXY->deepCopy());
}
else
{
rotatedXY = mFlipXY->deepCopy();
}
TIntermBinary *correctedOffset = new TIntermBinary(EOpMul, offsetNode, rotatedXY);
correctedOffset->setLine(offsetNode->getLine());
interpolateAtOffsetArguments->push_back(correctedOffset);
TIntermTyped *interpolateAtOffsetNode = CreateBuiltInFunctionCallNode(
"interpolateAtOffset", interpolateAtOffsetArguments, *symbolTable, shaderVersion);
interpolateAtOffsetNode->setLine(node->getLine());
// Replace the old node by this new node.
queueReplacement(interpolateAtOffsetNode, OriginalNode::IS_DROPPED);
return true;
}
} // anonymous namespace
bool RewriteInterpolateAtOffset(TCompiler *compiler,
TIntermNode *root,
const TSymbolTable &symbolTable,
int shaderVersion,
TIntermBinary *flipXY,
TIntermTyped *fragRotation)
{
// interpolateAtOffset is only valid in GLSL 3.0 and later.
if (shaderVersion < 300)
{
return true;
}
return Traverser::Apply(compiler, root, symbolTable, flipXY, fragRotation, shaderVersion);
}
} // 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.
//
// This mutating tree traversal flips the 2nd argument of interpolateAtOffset() to account for
// Y-coordinate flipping
//
// From: interpolateAtOffset(float interpolant, vec2 offset);
// To: interpolateAtOffset(float interpolant, vec2(offset * (pre-rotation * viewportYScale)));
//
// See http://anglebug.com/3589
#ifndef COMPILER_TRANSLATOR_TREEOPS_FLIP_INTERPOLATEATOFFSET_H_
#define COMPILER_TRANSLATOR_TREEOPS_FLIP_INTERPOLATEATOFFSET_H_
#include "common/angleutils.h"
namespace sh
{
class TCompiler;
class TIntermNode;
class TIntermBinary;
class TIntermTyped;
class TSymbolTable;
// If fragRotation = nullptr, no rotation will be applied.
ANGLE_NO_DISCARD bool RewriteInterpolateAtOffset(TCompiler *compiler,
TIntermNode *root,
const TSymbolTable &symbolTable,
int shaderVersion,
TIntermBinary *flipXY,
TIntermTyped *fragRotation);
} // namespace sh
#endif // COMPILER_TRANSLATOR_TREEOPS_FLIP_INTERPOLATEATOFFSET_H_
...@@ -185,12 +185,6 @@ ...@@ -185,12 +185,6 @@
// Cannot create 2D (array) view of 3D texture. // Cannot create 2D (array) view of 3D texture.
3886 VULKAN : dEQP-GLES31.functional.image_load_store.3d.*layer = FAIL 3886 VULKAN : dEQP-GLES31.functional.image_load_store.3d.*layer = FAIL
// Conflict between "interpolateAtOffset()" and the viewport transformation for a default framebuffer
3589 VULKAN : dEQP-GLES31.functional.shaders.multisample_interpolation.interpolate_at_offset.no_qualifiers.default_framebuffer = FAIL
3589 VULKAN : dEQP-GLES31.functional.shaders.multisample_interpolation.interpolate_at_offset.centroid_qualifier.default_framebuffer = FAIL
3589 VULKAN : dEQP-GLES31.functional.shaders.multisample_interpolation.interpolate_at_offset.sample_qualifier.default_framebuffer = FAIL
3589 VULKAN : dEQP-GLES31.functional.shaders.multisample_interpolation.interpolate_at_offset.array_element.default_framebuffer = FAIL
//// ////
//// Android (i.e. Pixel*) Vulkan expectations //// Android (i.e. Pixel*) Vulkan expectations
//// ////
......
...@@ -2166,6 +2166,186 @@ TEST_P(EGLPreRotationBlitFramebufferTest, FboDestOutOfBoundsSourceAndDestBlitFra ...@@ -2166,6 +2166,186 @@ TEST_P(EGLPreRotationBlitFramebufferTest, FboDestOutOfBoundsSourceAndDestBlitFra
ASSERT_EGL_SUCCESS(); ASSERT_EGL_SUCCESS();
} }
class EGLPreRotationInterpolateAtOffsetTest : public EGLPreRotationSurfaceTest
{
protected:
EGLPreRotationInterpolateAtOffsetTest() {}
GLuint createProgram()
{
// Init program
constexpr char kVS[] =
"#version 310 es\n"
"#extension GL_OES_shader_multisample_interpolation : require\n"
"in highp vec2 position;\n"
"uniform float screen_width;\n"
"uniform float screen_height;\n"
"out highp vec2 v_screenPosition;\n"
"out highp vec2 v_offset;\n"
"void main (void)\n"
"{\n"
" gl_Position = vec4(position, 0, 1);\n"
" v_screenPosition = (position.xy + vec2(1.0, 1.0)) / 2.0 * vec2(screen_width, "
"screen_height);\n"
" v_offset = position.xy * 0.5f;\n"
"}";
constexpr char kFS[] =
"#version 310 es\n"
"#extension GL_OES_shader_multisample_interpolation : require\n"
"in highp vec2 v_screenPosition;\n"
"in highp vec2 v_offset;\n"
"layout(location = 0) out mediump vec4 FragColor;\n"
"void main() {\n"
" const highp float threshold = 0.15625; // 4 subpixel bits. Assume 3 accurate bits "
"+ 0.03125 for other errors\n"
"\n"
" highp vec2 pixelCenter = floor(v_screenPosition) + vec2(0.5, 0.5);\n"
" highp vec2 offsetValue = interpolateAtOffset(v_screenPosition, v_offset);\n"
" highp vec2 refValue = pixelCenter + v_offset;\n"
"\n"
" bool valuesEqual = all(lessThan(abs(offsetValue - refValue), vec2(threshold)));\n"
" if (valuesEqual)\n"
" FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
" else\n"
" FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
"}";
return CompileProgram(kVS, kFS);
}
void initializeGeometry(GLuint program,
GLBuffer *indexBuffer,
GLVertexArray *vertexArray,
GLBuffer *vertexBuffers)
{
GLint positionLocation = glGetAttribLocation(program, "position");
ASSERT_NE(-1, positionLocation);
GLuint screenWidthId = glGetUniformLocation(program, "screen_width");
GLuint screenHeightId = glGetUniformLocation(program, "screen_height");
glUniform1f(screenWidthId, (GLfloat)mSize);
glUniform1f(screenHeightId, (GLfloat)mSize);
glBindVertexArray(*vertexArray);
std::vector<GLushort> indices = {0, 1, 2, 2, 3, 0};
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, *indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * indices.size(), &indices[0],
GL_STATIC_DRAW);
std::vector<GLfloat> positionData = {// quad vertices
-1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f};
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffers[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * positionData.size(), &positionData[0],
GL_STATIC_DRAW);
glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2,
nullptr);
glEnableVertexAttribArray(positionLocation);
}
};
// Draw with interpolateAtOffset() builtin function to pre-rotated default FBO
TEST_P(EGLPreRotationInterpolateAtOffsetTest, InterpolateAtOffsetWithDefaultFBO)
{
// http://anglebug.com/4453
ANGLE_SKIP_TEST_IF(isVulkanRenderer() && IsLinux() && IsIntel());
// Flaky on Linux SwANGLE http://anglebug.com/4453
ANGLE_SKIP_TEST_IF(IsLinux() && isSwiftshader());
// To aid in debugging, we want this window visible
setWindowVisible(mOSWindow, true);
initializeDisplay();
initializeSurfaceWithRGBA8888Config();
eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext);
ASSERT_EGL_SUCCESS();
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_shader_multisample_interpolation"));
// Init program
GLuint program = createProgram();
ASSERT_NE(0u, program);
glUseProgram(program);
GLBuffer indexBuffer;
GLVertexArray vertexArray;
GLBuffer vertexBuffers;
initializeGeometry(program, &indexBuffer, &vertexArray, &vertexBuffers);
ASSERT_GL_NO_ERROR();
glViewport(0, 0, mSize, mSize);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(0, 255, 0, 255));
EXPECT_PIXEL_COLOR_EQ(mSize - 1, 0, GLColor(0, 255, 0, 255));
EXPECT_PIXEL_COLOR_EQ(0, mSize - 1, GLColor(0, 255, 0, 255));
EXPECT_PIXEL_COLOR_EQ(mSize - 1, mSize - 1, GLColor(0, 255, 0, 255));
ASSERT_GL_NO_ERROR();
// Make the image visible
eglSwapBuffers(mDisplay, mWindowSurface);
ASSERT_EGL_SUCCESS();
}
// Draw with interpolateAtOffset() builtin function to pre-rotated custom FBO
TEST_P(EGLPreRotationInterpolateAtOffsetTest, InterpolateAtOffsetWithCustomFBO)
{
// http://anglebug.com/4453
ANGLE_SKIP_TEST_IF(isVulkanRenderer() && IsLinux() && IsIntel());
// Flaky on Linux SwANGLE http://anglebug.com/4453
ANGLE_SKIP_TEST_IF(IsLinux() && isSwiftshader());
// To aid in debugging, we want this window visible
setWindowVisible(mOSWindow, true);
initializeDisplay();
initializeSurfaceWithRGBA8888Config();
eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext);
ASSERT_EGL_SUCCESS();
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_shader_multisample_interpolation"));
// Init program
GLuint program = createProgram();
ASSERT_NE(0u, program);
glUseProgram(program);
GLBuffer indexBuffer;
GLVertexArray vertexArray;
GLBuffer vertexBuffers;
initializeGeometry(program, &indexBuffer, &vertexArray, &vertexBuffers);
ASSERT_GL_NO_ERROR();
// Create a texture-backed FBO
GLFramebuffer fbo;
GLTexture texture;
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, mSize, mSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
ASSERT_GL_NO_ERROR();
glViewport(0, 0, mSize, mSize);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(0, 255, 0, 255));
EXPECT_PIXEL_COLOR_EQ(mSize - 1, 0, GLColor(0, 255, 0, 255));
EXPECT_PIXEL_COLOR_EQ(0, mSize - 1, GLColor(0, 255, 0, 255));
EXPECT_PIXEL_COLOR_EQ(mSize - 1, mSize - 1, GLColor(0, 255, 0, 255));
ASSERT_GL_NO_ERROR();
}
} // anonymous namespace } // anonymous namespace
#ifdef Bool #ifdef Bool
...@@ -2173,6 +2353,10 @@ TEST_P(EGLPreRotationBlitFramebufferTest, FboDestOutOfBoundsSourceAndDestBlitFra ...@@ -2173,6 +2353,10 @@ TEST_P(EGLPreRotationBlitFramebufferTest, FboDestOutOfBoundsSourceAndDestBlitFra
# undef Bool # undef Bool
#endif #endif
ANGLE_INSTANTIATE_TEST_COMBINE_1(EGLPreRotationInterpolateAtOffsetTest,
PrintToStringParamName,
testing::Bool(),
WithNoFixture(ES31_VULKAN()));
ANGLE_INSTANTIATE_TEST_COMBINE_1(EGLPreRotationSurfaceTest, ANGLE_INSTANTIATE_TEST_COMBINE_1(EGLPreRotationSurfaceTest,
PrintToStringParamName, PrintToStringParamName,
testing::Bool(), testing::Bool(),
......
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