| // | |
| // Copyright 2019 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. | |
| // | |
| // DrawBaseVertexBaseInstanceTest: Tests of GL_ANGLE_base_vertex_base_instance | |
| #include "gpu_info_util/SystemInfo.h" | |
| #include "test_utils/ANGLETest.h" | |
| #include "test_utils/gl_raii.h" | |
| #include <numeric> | |
| using namespace angle; | |
| namespace | |
| { | |
| // Create a kWidth * kHeight canvas equally split into kCountX * kCountY tiles | |
| // each containing a quad partially covering each tile | |
| constexpr uint32_t kWidth = 256; | |
| constexpr uint32_t kHeight = 256; | |
| constexpr uint32_t kCountX = 8; | |
| constexpr uint32_t kCountY = 8; | |
| constexpr std::array<GLfloat, 2> kTileSize = { | |
| 1.f / static_cast<GLfloat>(kCountX), | |
| 1.f / static_cast<GLfloat>(kCountY), | |
| }; | |
| constexpr std::array<uint32_t, 2> kTilePixelSize = {kWidth / kCountX, kHeight / kCountY}; | |
| constexpr std::array<GLfloat, 2> kQuadRadius = {0.25f * kTileSize[0], 0.25f * kTileSize[1]}; | |
| constexpr std::array<uint32_t, 2> kPixelCheckSize = { | |
| static_cast<uint32_t>(kQuadRadius[0] * kWidth), | |
| static_cast<uint32_t>(kQuadRadius[1] * kHeight)}; | |
| constexpr std::array<GLfloat, 2> getTileCenter(uint32_t x, uint32_t y) | |
| { | |
| return { | |
| kTileSize[0] * (0.5f + static_cast<GLfloat>(x)), | |
| kTileSize[1] * (0.5f + static_cast<GLfloat>(y)), | |
| }; | |
| } | |
| constexpr std::array<std::array<GLfloat, 3>, 4> getQuadVertices(uint32_t x, uint32_t y) | |
| { | |
| const auto center = getTileCenter(x, y); | |
| return { | |
| std::array<GLfloat, 3>{center[0] - kQuadRadius[0], center[1] - kQuadRadius[1], 0.0f}, | |
| std::array<GLfloat, 3>{center[0] + kQuadRadius[0], center[1] - kQuadRadius[1], 0.0f}, | |
| std::array<GLfloat, 3>{center[0] + kQuadRadius[0], center[1] + kQuadRadius[1], 0.0f}, | |
| std::array<GLfloat, 3>{center[0] - kQuadRadius[0], center[1] + kQuadRadius[1], 0.0f}, | |
| }; | |
| } | |
| enum class BaseVertexOption | |
| { | |
| NoBaseVertex, | |
| UseBaseVertex | |
| }; | |
| enum class BaseInstanceOption | |
| { | |
| NoBaseInstance, | |
| UseBaseInstance | |
| }; | |
| using DrawBaseVertexBaseInstanceTestParams = | |
| std::tuple<angle::PlatformParameters, BaseVertexOption, BaseInstanceOption>; | |
| struct PrintToStringParamName | |
| { | |
| std::string operator()( | |
| const ::testing::TestParamInfo<DrawBaseVertexBaseInstanceTestParams> &info) const | |
| { | |
| ::std::stringstream ss; | |
| ss << (std::get<2>(info.param) == BaseInstanceOption::UseBaseInstance ? "UseBaseInstance_" | |
| : "") | |
| << (std::get<1>(info.param) == BaseVertexOption::UseBaseVertex ? "UseBaseVertex_" : "") | |
| << std::get<0>(info.param); | |
| return ss.str(); | |
| } | |
| }; | |
| // These tests check correctness of the ANGLE_base_vertex_base_instance extension. | |
| // An array of quads is drawn across the screen. | |
| // gl_VertexID, gl_InstanceID, gl_BaseVertex, and gl_BaseInstance | |
| // are checked by using them to select the color of the draw. | |
| class DrawBaseVertexBaseInstanceTest | |
| : public ANGLETestBase, | |
| public ::testing::TestWithParam<DrawBaseVertexBaseInstanceTestParams> | |
| { | |
| protected: | |
| DrawBaseVertexBaseInstanceTest() : ANGLETestBase(std::get<0>(GetParam())) | |
| { | |
| setWindowWidth(kWidth); | |
| setWindowHeight(kHeight); | |
| setConfigRedBits(8); | |
| setConfigGreenBits(8); | |
| setConfigBlueBits(8); | |
| setConfigAlphaBits(8); | |
| // Rects in the same column are within a vertex array, testing gl_VertexID, gl_BaseVertex | |
| // Rects in the same row are drawn by instancing, testing gl_InstanceID, gl_BaseInstance | |
| mIndices = {0, 1, 2, 0, 2, 3}; | |
| for (uint32_t y = 0; y < kCountY; ++y) | |
| { | |
| // v3 ---- v2 | |
| // | | | |
| // | | | |
| // v0 ---- v1 | |
| const auto vs = getQuadVertices(0, y); | |
| for (const auto &v : vs) | |
| { | |
| mVertices.insert(mVertices.end(), v.begin(), v.end()); | |
| } | |
| for (GLushort i : mIndices) | |
| { | |
| mNonIndexedVertices.insert(mNonIndexedVertices.end(), vs[i].begin(), vs[i].end()); | |
| } | |
| } | |
| mRegularIndices.resize(kCountY * mIndices.size()); | |
| for (uint32_t i = 0; i < kCountY; i++) | |
| { | |
| uint32_t oi = 6 * i; | |
| uint32_t ov = 4 * i; | |
| for (uint32_t j = 0; j < 6; j++) | |
| { | |
| mRegularIndices[oi + j] = mIndices[j] + ov; | |
| } | |
| } | |
| std::iota(mInstancedArrayId.begin(), mInstancedArrayId.end(), 0.0f); | |
| std::reverse_copy(mInstancedArrayId.begin(), mInstancedArrayId.end(), | |
| mInstancedArrayColorId.begin()); | |
| } | |
| void SetUp() override { ANGLETestBase::ANGLETestSetUp(); } | |
| bool useBaseVertexBuiltin() const | |
| { | |
| return std::get<1>(GetParam()) == BaseVertexOption::UseBaseVertex; | |
| } | |
| bool useBaseInstanceBuiltin() const | |
| { | |
| return std::get<2>(GetParam()) == BaseInstanceOption::UseBaseInstance; | |
| } | |
| std::string vertexShaderSource300(bool isDrawArrays, bool isMultiDraw, bool divisorTest) | |
| { | |
| // Each color channel is to test the value of | |
| // R: gl_InstanceID and gl_BaseInstance | |
| // G: gl_VertexID and gl_BaseVertex | |
| // B: gl_BaseVertex | |
| std::stringstream shader; | |
| shader << ("#version 300 es\n") | |
| << (isMultiDraw ? "#extension GL_ANGLE_multi_draw : require\n" : "") | |
| << ("#extension GL_ANGLE_base_vertex_base_instance : require\n") | |
| << "#define kCountX " << kCountX << "\n" | |
| << "#define kCountY " << kCountY << "\n" | |
| << R"( | |
| in vec2 vPosition; | |
| )" << (useBaseInstanceBuiltin() ? "" : "in float vInstanceID;\n") | |
| << (!divisorTest ? "" : "in float vInstanceColorID;\n") << R"( | |
| out vec4 color; | |
| void main() | |
| { | |
| const float xStep = 1.0 / float(kCountX); | |
| const float yStep = 1.0 / float(kCountY); | |
| float x_id = )" | |
| << (useBaseInstanceBuiltin() ? " float(gl_InstanceID + gl_BaseInstance);" | |
| : "vInstanceID;") | |
| << "float x_color = " | |
| << (divisorTest ? "xStep * (vInstanceColorID + 1.0f);" : " 1.0 - xStep * x_id;") | |
| << R"( | |
| float y_id = floor(float(gl_VertexID) / )" | |
| << (isDrawArrays ? "6.0" : "4.0") << R"( + 0.01); | |
| color = vec4( | |
| x_color, | |
| 1.0 - yStep * y_id, | |
| )" << (useBaseVertexBuiltin() ? "1.0 - yStep * float(gl_BaseVertex) / 4.0" : "1.0") | |
| << R"(, | |
| 1); | |
| mat3 transform = mat3(1.0); | |
| transform[2][0] = x_id * xStep; | |
| gl_Position = vec4(transform * vec3(vPosition, 1.0) * 2.0 - 1.0, 1); | |
| })"; | |
| return shader.str(); | |
| } | |
| std::string fragmentShaderSource300() | |
| { | |
| return | |
| R"(#version 300 es | |
| precision mediump float; | |
| in vec4 color; | |
| out vec4 o_color; | |
| void main() | |
| { | |
| o_color = color; | |
| })"; | |
| } | |
| void setupProgram(GLProgram &program, | |
| bool isDrawArrays = true, | |
| bool isMultiDraw = false, | |
| bool isDivisorTest = false) | |
| { | |
| program.makeRaster(vertexShaderSource300(isDrawArrays, isMultiDraw, isDivisorTest).c_str(), | |
| fragmentShaderSource300().c_str()); | |
| EXPECT_GL_NO_ERROR(); | |
| ASSERT_TRUE(program.valid()); | |
| glUseProgram(program.get()); | |
| mPositionLoc = glGetAttribLocation(program.get(), "vPosition"); | |
| if (!useBaseInstanceBuiltin()) | |
| { | |
| mInstanceIDLoc = glGetAttribLocation(program.get(), "vInstanceID"); | |
| mInstanceColorIDLoc = glGetAttribLocation(program.get(), "vInstanceColorID"); | |
| } | |
| } | |
| void setupNonIndexedBuffers(GLBuffer &vertexBuffer) | |
| { | |
| glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.get()); | |
| glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * mNonIndexedVertices.size(), | |
| mNonIndexedVertices.data(), GL_STATIC_DRAW); | |
| ASSERT_GL_NO_ERROR(); | |
| } | |
| void setupIndexedBuffers(GLBuffer &vertexBuffer, GLBuffer &indexBuffer) | |
| { | |
| glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); | |
| glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * mVertices.size(), mVertices.data(), | |
| GL_STATIC_DRAW); | |
| glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); | |
| glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * mIndices.size(), mIndices.data(), | |
| GL_STATIC_DRAW); | |
| ASSERT_GL_NO_ERROR(); | |
| } | |
| void setupInstanceIDBuffer(GLBuffer &instanceIDBuffer) | |
| { | |
| glBindBuffer(GL_ARRAY_BUFFER, instanceIDBuffer); | |
| glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * mInstancedArrayId.size(), | |
| mInstancedArrayId.data(), GL_STATIC_DRAW); | |
| ASSERT_GL_NO_ERROR(); | |
| } | |
| void setupInstanceColorIDBuffer(GLBuffer &instanceIDBuffer) | |
| { | |
| glBindBuffer(GL_ARRAY_BUFFER, instanceIDBuffer); | |
| glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * mInstancedArrayColorId.size(), | |
| mInstancedArrayColorId.data(), GL_STATIC_DRAW); | |
| ASSERT_GL_NO_ERROR(); | |
| } | |
| void setupRegularIndexedBuffer(GLBuffer &indexBuffer) | |
| { | |
| glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); | |
| glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * mRegularIndices.size(), | |
| mRegularIndices.data(), GL_STATIC_DRAW); | |
| ASSERT_GL_NO_ERROR(); | |
| } | |
| void setupPositionVertexAttribPointer() | |
| { | |
| glEnableVertexAttribArray(mPositionLoc); | |
| glVertexAttribPointer(mPositionLoc, 3, GL_FLOAT, GL_FALSE, 0, 0); | |
| } | |
| void setupInstanceIDVertexAttribPointer(GLuint instanceIDLoc) | |
| { | |
| glEnableVertexAttribArray(instanceIDLoc); | |
| glVertexAttribPointer(instanceIDLoc, 1, GL_FLOAT, GL_FALSE, 0, 0); | |
| glVertexAttribDivisor(instanceIDLoc, 1); | |
| } | |
| void doDrawArraysInstancedBaseInstance() | |
| { | |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |
| const uint32_t countPerDraw = kCountY * 6; | |
| for (uint32_t i = 0; i < kCountX; i += 2) | |
| { | |
| glDrawArraysInstancedBaseInstanceANGLE(GL_TRIANGLES, 0, countPerDraw, 2, i); | |
| } | |
| } | |
| void doMultiDrawArraysInstancedBaseInstance() | |
| { | |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |
| const uint32_t countPerDraw = kCountY * 6; | |
| const GLsizei drawCount = kCountX / 2; | |
| const std::vector<GLsizei> counts(drawCount, countPerDraw); | |
| const std::vector<GLsizei> firsts(drawCount, 0); | |
| const std::vector<GLsizei> instanceCounts(drawCount, 2); | |
| std::vector<GLuint> baseInstances(drawCount); | |
| for (size_t i = 0; i < drawCount; i++) | |
| { | |
| baseInstances[i] = i * 2; | |
| } | |
| glMultiDrawArraysInstancedBaseInstanceANGLE(GL_TRIANGLES, firsts.data(), counts.data(), | |
| instanceCounts.data(), baseInstances.data(), | |
| drawCount); | |
| } | |
| void doDrawElementsInstancedBaseVertexBaseInstance() | |
| { | |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |
| const uint32_t countPerDraw = 6; | |
| for (uint32_t v = 0; v < kCountY; v++) | |
| { | |
| for (uint32_t i = 0; i < kCountX; i += 2) | |
| { | |
| glDrawElementsInstancedBaseVertexBaseInstanceANGLE( | |
| GL_TRIANGLES, countPerDraw, GL_UNSIGNED_SHORT, | |
| reinterpret_cast<GLvoid *>(static_cast<uintptr_t>(0)), 2, v * 4, i); | |
| } | |
| } | |
| } | |
| // Call this after the *BaseVertexBaseInstance draw call to check if value of BaseVertex and | |
| // BaseInstance are reset to zero | |
| void doDrawArraysBaseInstanceReset() | |
| { | |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |
| glDrawArrays(GL_TRIANGLES, 0, 6 * kCountY); | |
| } | |
| void doDrawElementsBaseVertexBaseInstanceReset() | |
| { | |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |
| glDrawElements(GL_TRIANGLES, 6 * kCountY, GL_UNSIGNED_SHORT, | |
| reinterpret_cast<GLvoid *>(static_cast<uintptr_t>(0))); | |
| } | |
| void doMultiDrawElementsInstancedBaseVertexBaseInstance() | |
| { | |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |
| const GLsizei drawCount = kCountX * kCountY / 2; | |
| const std::vector<GLsizei> counts(drawCount, 6); | |
| const std::vector<GLsizei> instanceCounts(drawCount, 2); | |
| const std::vector<GLvoid *> indices(drawCount, 0); | |
| std::vector<GLint> baseVertices(drawCount); | |
| std::vector<GLuint> baseInstances(drawCount); | |
| GLsizei b = 0; | |
| for (uint32_t v = 0; v < kCountY; v++) | |
| { | |
| for (uint32_t i = 0; i < kCountX; i += 2) | |
| { | |
| baseVertices[b] = v * 4; | |
| baseInstances[b] = i; | |
| b++; | |
| } | |
| } | |
| glMultiDrawElementsInstancedBaseVertexBaseInstanceANGLE( | |
| GL_TRIANGLES, counts.data(), GL_UNSIGNED_SHORT, indices.data(), instanceCounts.data(), | |
| baseVertices.data(), baseInstances.data(), drawCount); | |
| } | |
| void checkDrawResult(bool hasBaseVertex, bool oneColumn = false) | |
| { | |
| uint32_t numColums = oneColumn ? 1 : kCountX; | |
| for (uint32_t y = 0; y < kCountY; ++y) | |
| { | |
| for (uint32_t x = 0; x < numColums; ++x) | |
| { | |
| uint32_t center_x = x * kTilePixelSize[0] + kTilePixelSize[0] / 2; | |
| uint32_t center_y = y * kTilePixelSize[1] + kTilePixelSize[1] / 2; | |
| EXPECT_PIXEL_NEAR(center_x - kPixelCheckSize[0] / 2, | |
| center_y - kPixelCheckSize[1] / 2, | |
| 256.0 * (1.0 - (float)x / (float)kCountX), | |
| 256.0 * (1.0 - (float)y / (float)kCountY), | |
| useBaseVertexBuiltin() && hasBaseVertex && !oneColumn | |
| ? 256.0 * (1.0 - (float)y / (float)kCountY) | |
| : 255, | |
| 255, 3); | |
| } | |
| } | |
| } | |
| void TearDown() override { ANGLETestBase::ANGLETestTearDown(); } | |
| bool requestDrawBaseVertexBaseInstanceExtension() | |
| { | |
| if (IsGLExtensionRequestable("GL_ANGLE_base_vertex_base_instance")) | |
| { | |
| glRequestExtensionANGLE("GL_ANGLE_base_vertex_base_instance"); | |
| } | |
| if (!IsGLExtensionEnabled("GL_ANGLE_base_vertex_base_instance")) | |
| { | |
| return false; | |
| } | |
| return true; | |
| } | |
| bool requestInstancedExtension() | |
| { | |
| if (IsGLExtensionRequestable("GL_ANGLE_instanced_arrays")) | |
| { | |
| glRequestExtensionANGLE("GL_ANGLE_instanced_arrays"); | |
| } | |
| if (!IsGLExtensionEnabled("GL_ANGLE_instanced_arrays")) | |
| { | |
| return false; | |
| } | |
| return true; | |
| } | |
| bool requestExtensions() | |
| { | |
| if (getClientMajorVersion() <= 2) | |
| { | |
| if (!requestInstancedExtension()) | |
| { | |
| return false; | |
| } | |
| } | |
| return requestDrawBaseVertexBaseInstanceExtension(); | |
| } | |
| // Used for base vertex base instance draw calls | |
| std::vector<GLushort> mIndices; | |
| std::vector<GLfloat> mVertices; | |
| std::vector<GLfloat> mNonIndexedVertices; | |
| // Used when gl_BaseInstance is not used | |
| std::array<GLfloat, kCountX> mInstancedArrayId; | |
| std::array<GLfloat, kCountX> mInstancedArrayColorId; | |
| // Used for regular draw calls without base vertex base instance | |
| std::vector<GLushort> mRegularIndices; | |
| GLint mPositionLoc; | |
| GLuint mInstanceIDLoc; | |
| GLuint mInstanceColorIDLoc; | |
| }; | |
| // Tests that compile a program with the extension succeeds | |
| TEST_P(DrawBaseVertexBaseInstanceTest, CanCompile) | |
| { | |
| ANGLE_SKIP_TEST_IF(!requestExtensions()); | |
| GLProgram p0; | |
| setupProgram(p0, true, false); | |
| GLProgram p1; | |
| setupProgram(p1, true, true); | |
| GLProgram p2; | |
| setupProgram(p2, false, false); | |
| GLProgram p3; | |
| setupProgram(p3, false, true); | |
| } | |
| // Tests if baseInstance works properly with instanced array with non-zero divisor | |
| TEST_P(DrawBaseVertexBaseInstanceTest, BaseInstanceDivisor) | |
| { | |
| ANGLE_SKIP_TEST_IF(!requestExtensions()); | |
| ANGLE_SKIP_TEST_IF(useBaseInstanceBuiltin()); | |
| GLProgram program; | |
| setupProgram(program, true, false, true); | |
| GLBuffer nonIndexedVertexBuffer; | |
| setupNonIndexedBuffers(nonIndexedVertexBuffer); | |
| setupPositionVertexAttribPointer(); | |
| GLBuffer instanceIDBuffer; | |
| GLBuffer instanceColorIDBuffer; | |
| setupInstanceIDBuffer(instanceIDBuffer); | |
| setupInstanceIDVertexAttribPointer(mInstanceIDLoc); | |
| setupInstanceColorIDBuffer(instanceColorIDBuffer); | |
| setupInstanceIDVertexAttribPointer(mInstanceColorIDLoc); | |
| doDrawArraysInstancedBaseInstance(); | |
| EXPECT_GL_NO_ERROR(); | |
| checkDrawResult(false); | |
| doDrawArraysBaseInstanceReset(); | |
| EXPECT_GL_NO_ERROR(); | |
| checkDrawResult(false, true); | |
| GLProgram programIndexed; | |
| setupProgram(programIndexed, false, false, true); | |
| GLBuffer indexBuffer; | |
| GLBuffer vertexBuffer; | |
| setupIndexedBuffers(vertexBuffer, indexBuffer); | |
| setupPositionVertexAttribPointer(); | |
| glBindBuffer(GL_ARRAY_BUFFER, instanceIDBuffer); | |
| setupInstanceIDVertexAttribPointer(mInstanceIDLoc); | |
| glBindBuffer(GL_ARRAY_BUFFER, instanceColorIDBuffer); | |
| setupInstanceIDVertexAttribPointer(mInstanceColorIDLoc); | |
| doDrawElementsInstancedBaseVertexBaseInstance(); | |
| EXPECT_GL_NO_ERROR(); | |
| checkDrawResult(true); | |
| setupRegularIndexedBuffer(indexBuffer); | |
| doDrawElementsBaseVertexBaseInstanceReset(); | |
| EXPECT_GL_NO_ERROR(); | |
| checkDrawResult(false, true); | |
| } | |
| // Tests basic functionality of glDrawArraysInstancedBaseInstance | |
| TEST_P(DrawBaseVertexBaseInstanceTest, DrawArraysInstancedBaseInstance) | |
| { | |
| // TODO(shrekshao): Temporarily skip this test | |
| // before we could try updating win AMD bot driver version | |
| // after Lab team fixed issues with ssh into bot machines | |
| // Currently this test fail on certain Win7/Win2008Server AMD GPU | |
| // with driver version 23.20.185.235 when using OpenGL backend. | |
| // This failure couldn't be produced on local Win10 AMD machine with latest driver installed | |
| // Same for the MultiDrawArraysInstancedBaseInstance test | |
| if (IsAMD() && IsWindows() && IsDesktopOpenGL()) | |
| { | |
| SystemInfo *systemInfo = GetTestSystemInfo(); | |
| if (!(systemInfo->activeGPUIndex < 0 || systemInfo->gpus.empty())) | |
| { | |
| ANGLE_SKIP_TEST_IF(0x6613 == systemInfo->gpus[systemInfo->activeGPUIndex].deviceId); | |
| } | |
| } | |
| ANGLE_SKIP_TEST_IF(!requestExtensions()); | |
| GLProgram program; | |
| setupProgram(program, true); | |
| GLBuffer vertexBuffer; | |
| setupNonIndexedBuffers(vertexBuffer); | |
| setupPositionVertexAttribPointer(); | |
| GLBuffer instanceIDBuffer; | |
| if (!useBaseInstanceBuiltin()) | |
| { | |
| setupInstanceIDBuffer(instanceIDBuffer); | |
| setupInstanceIDVertexAttribPointer(mInstanceIDLoc); | |
| } | |
| doDrawArraysInstancedBaseInstance(); | |
| EXPECT_GL_NO_ERROR(); | |
| checkDrawResult(false); | |
| doDrawArraysBaseInstanceReset(); | |
| checkDrawResult(false, true); | |
| } | |
| // Tests basic functionality of glMultiDrawArraysInstancedBaseInstance | |
| TEST_P(DrawBaseVertexBaseInstanceTest, MultiDrawArraysInstancedBaseInstance) | |
| { | |
| if (IsAMD() && IsWindows() && IsDesktopOpenGL()) | |
| { | |
| SystemInfo *systemInfo = GetTestSystemInfo(); | |
| if (!(systemInfo->activeGPUIndex < 0 || systemInfo->gpus.empty())) | |
| { | |
| ANGLE_SKIP_TEST_IF(0x6613 == systemInfo->gpus[systemInfo->activeGPUIndex].deviceId); | |
| } | |
| } | |
| ANGLE_SKIP_TEST_IF(!requestExtensions()); | |
| GLProgram program; | |
| setupProgram(program, true, true); | |
| GLBuffer vertexBuffer; | |
| setupNonIndexedBuffers(vertexBuffer); | |
| setupPositionVertexAttribPointer(); | |
| GLBuffer instanceIDBuffer; | |
| if (!useBaseInstanceBuiltin()) | |
| { | |
| setupInstanceIDBuffer(instanceIDBuffer); | |
| setupInstanceIDVertexAttribPointer(mInstanceIDLoc); | |
| } | |
| doMultiDrawArraysInstancedBaseInstance(); | |
| EXPECT_GL_NO_ERROR(); | |
| checkDrawResult(false); | |
| doDrawArraysBaseInstanceReset(); | |
| checkDrawResult(false, true); | |
| } | |
| // Tests basic functionality of glDrawElementsInstancedBaseVertexBaseInstance | |
| TEST_P(DrawBaseVertexBaseInstanceTest, DrawElementsInstancedBaseVertexBaseInstance) | |
| { | |
| ANGLE_SKIP_TEST_IF(!requestExtensions()); | |
| GLProgram program; | |
| setupProgram(program, false); | |
| GLBuffer indexBuffer; | |
| GLBuffer vertexBuffer; | |
| setupIndexedBuffers(vertexBuffer, indexBuffer); | |
| setupPositionVertexAttribPointer(); | |
| GLBuffer instanceIDBuffer; | |
| if (!useBaseInstanceBuiltin()) | |
| { | |
| setupInstanceIDBuffer(instanceIDBuffer); | |
| setupInstanceIDVertexAttribPointer(mInstanceIDLoc); | |
| } | |
| doDrawElementsInstancedBaseVertexBaseInstance(); | |
| EXPECT_GL_NO_ERROR(); | |
| checkDrawResult(true); | |
| setupRegularIndexedBuffer(indexBuffer); | |
| doDrawElementsBaseVertexBaseInstanceReset(); | |
| EXPECT_GL_NO_ERROR(); | |
| checkDrawResult(true, true); | |
| } | |
| // Tests basic functionality of glMultiDrawElementsInstancedBaseVertexBaseInstance | |
| TEST_P(DrawBaseVertexBaseInstanceTest, MultiDrawElementsInstancedBaseVertexBaseInstance) | |
| { | |
| ANGLE_SKIP_TEST_IF(!requestExtensions()); | |
| GLProgram program; | |
| setupProgram(program, false, true); | |
| GLBuffer indexBuffer; | |
| GLBuffer vertexBuffer; | |
| setupIndexedBuffers(vertexBuffer, indexBuffer); | |
| setupPositionVertexAttribPointer(); | |
| GLBuffer instanceIDBuffer; | |
| if (!useBaseInstanceBuiltin()) | |
| { | |
| setupInstanceIDBuffer(instanceIDBuffer); | |
| setupInstanceIDVertexAttribPointer(mInstanceIDLoc); | |
| } | |
| doMultiDrawElementsInstancedBaseVertexBaseInstance(); | |
| EXPECT_GL_NO_ERROR(); | |
| checkDrawResult(true); | |
| setupRegularIndexedBuffer(indexBuffer); | |
| doDrawElementsBaseVertexBaseInstanceReset(); | |
| EXPECT_GL_NO_ERROR(); | |
| checkDrawResult(true, true); | |
| } | |
| const angle::PlatformParameters platforms[] = { | |
| ES3_D3D11(), | |
| ES3_OPENGL(), | |
| ES3_OPENGLES(), | |
| ES3_VULKAN(), | |
| }; | |
| INSTANTIATE_TEST_SUITE_P( | |
| , | |
| DrawBaseVertexBaseInstanceTest, | |
| testing::Combine( | |
| testing::ValuesIn(::angle::FilterTestParams(platforms, ArraySize(platforms))), | |
| testing::Values(BaseVertexOption::NoBaseVertex, BaseVertexOption::UseBaseVertex), | |
| testing::Values(BaseInstanceOption::NoBaseInstance, BaseInstanceOption::UseBaseInstance)), | |
| PrintToStringParamName()); | |
| } // namespace |