Hash :
001c7e8c
Author :
Date :
2020-09-21T13:25:46
Vulkan: Link PPO during draw validation From the OpenGL ES 3.1 spec: 11.1.3.11 Validation It is not always possible to determine at link time if a program object can execute successfully, given that LinkProgram can not know the state of the remainder of the pipeline. Therefore validation is done when the first rendering command which triggers shader invocations is issued, to determine if the set of active program objects can be executed. For draws, this CL moves the PPO link operation to ValidateDrawStates() to generate PPO link failures within ANGLE's validation layer, so we fail any rendering commands during command validation. For dispatch, PPOs are linked during Context::prepareForDispatch(), where the PPO is converted from draw to compute, since that conversion requires a re-link. This re-link shouldn't fail due to errors that would have been caught during validation, since the compute shader must have successfully linked before it can be included in the PPO in the first place. We don't re-link when converting back to draw, since it's possible there are validation errors (which we want to catch during validation of the next rendering command). Bug: angleproject:5064 Test: dEQP.GLES31/functional_separate_shader_validation_es31_* Test: ContextNoErrorTest31.DrawWithPPO Test: ProgramPipelineTest31.VerifyPpoLinkErrorSignalledCorrectly Change-Id: Ibb249e893c007a83cc6b813f848a660bfa34ecb0 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2422375 Commit-Queue: Tim Van Patten <timvp@google.com> Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: Jamie Madill <jmadill@chromium.org> Reviewed-by: Ian Elliott <ianelliott@google.com>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
//
// 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.
//
// ContextNoErrorTest:
// Tests pertaining to GL_KHR_no_error
//
#include <gtest/gtest.h>
#include "common/platform.h"
#include "test_utils/ANGLETest.h"
#include "test_utils/gl_raii.h"
using namespace angle;
class ContextNoErrorTest : public ANGLETest
{
protected:
ContextNoErrorTest() : mNaughtyTexture(0) { setNoErrorEnabled(true); }
void testTearDown() override
{
if (mNaughtyTexture != 0)
{
glDeleteTextures(1, &mNaughtyTexture);
}
}
void bindNaughtyTexture()
{
glGenTextures(1, &mNaughtyTexture);
ASSERT_GL_NO_ERROR();
glBindTexture(GL_TEXTURE_CUBE_MAP, mNaughtyTexture);
ASSERT_GL_NO_ERROR();
// mNaughtyTexture should now be a GL_TEXTURE_CUBE_MAP texture, so rebinding it to
// GL_TEXTURE_2D is an error
glBindTexture(GL_TEXTURE_2D, mNaughtyTexture);
}
GLuint mNaughtyTexture;
};
class ContextNoErrorTest31 : public ContextNoErrorTest
{
protected:
~ContextNoErrorTest31()
{
glDeleteProgram(mVertProg);
glDeleteProgram(mFragProg);
glDeleteProgramPipelines(1, &mPipeline);
}
void bindProgramPipeline(const GLchar *vertString, const GLchar *fragString);
void drawQuadWithPPO(const std::string &positionAttribName,
const GLfloat positionAttribZ,
const GLfloat positionAttribXYScale);
GLuint mVertProg;
GLuint mFragProg;
GLuint mPipeline;
};
void ContextNoErrorTest31::bindProgramPipeline(const GLchar *vertString, const GLchar *fragString)
{
mVertProg = glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &vertString);
ASSERT_NE(mVertProg, 0u);
mFragProg = glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &fragString);
ASSERT_NE(mFragProg, 0u);
// Generate a program pipeline and attach the programs to their respective stages
glGenProgramPipelines(1, &mPipeline);
EXPECT_GL_NO_ERROR();
glUseProgramStages(mPipeline, GL_VERTEX_SHADER_BIT, mVertProg);
EXPECT_GL_NO_ERROR();
glUseProgramStages(mPipeline, GL_FRAGMENT_SHADER_BIT, mFragProg);
EXPECT_GL_NO_ERROR();
glBindProgramPipeline(mPipeline);
EXPECT_GL_NO_ERROR();
}
void ContextNoErrorTest31::drawQuadWithPPO(const std::string &positionAttribName,
const GLfloat positionAttribZ,
const GLfloat positionAttribXYScale)
{
glUseProgram(0);
std::array<Vector3, 6> quadVertices = ANGLETestBase::GetQuadVertices();
for (Vector3 &vertex : quadVertices)
{
vertex.x() *= positionAttribXYScale;
vertex.y() *= positionAttribXYScale;
vertex.z() = positionAttribZ;
}
GLint positionLocation = glGetAttribLocation(mVertProg, positionAttribName.c_str());
glBindBuffer(GL_ARRAY_BUFFER, 0);
glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, quadVertices.data());
glEnableVertexAttribArray(positionLocation);
glDrawArrays(GL_TRIANGLES, 0, 6);
glDisableVertexAttribArray(positionLocation);
glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
}
// Tests that error reporting is suppressed when GL_KHR_no_error is enabled
TEST_P(ContextNoErrorTest, NoError)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_KHR_no_error"));
bindNaughtyTexture();
EXPECT_GL_NO_ERROR();
}
// Tests that we can draw with a program pipeline when GL_KHR_no_error is enabled.
TEST_P(ContextNoErrorTest31, DrawWithPPO)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_KHR_no_error"));
// Only the Vulkan backend supports PPOs
ANGLE_SKIP_TEST_IF(!IsVulkan());
// TODO(http://anglebug.com/5102): Linking PPOs is currently done during draw call validation,
// so drawing with a PPO fails without validation enabled.
ANGLE_SKIP_TEST_IF(IsGLExtensionEnabled("GL_KHR_no_error"));
// Create two separable program objects from a
// single source string respectively (vertSrc and fragSrc)
const GLchar *vertString = essl31_shaders::vs::Simple();
const GLchar *fragString = essl31_shaders::fs::Red();
bindProgramPipeline(vertString, fragString);
drawQuadWithPPO("a_position", 0.5f, 1.0f);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
}
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(ContextNoErrorTest);
ANGLE_INSTANTIATE_TEST_ES31(ContextNoErrorTest31);