| // |
| // 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. |
| // |
| // VulkanPerformanceCounterTest: |
| // Validates specific GL call patterns with ANGLE performance counters. |
| // For example we can verify a certain call set doesn't break the RenderPass. |
| |
| #include "test_utils/ANGLETest.h" |
| #include "test_utils/angle_test_instantiate.h" |
| // 'None' is defined as 'struct None {};' in |
| // third_party/googletest/src/googletest/include/gtest/internal/gtest-type-util.h. |
| // But 'None' is also defined as a numeric constant 0L in <X11/X.h>. |
| // So we need to include ANGLETest.h first to avoid this conflict. |
| |
| #include "include/platform/Feature.h" |
| #include "test_utils/gl_raii.h" |
| #include "util/random_utils.h" |
| #include "util/shader_utils.h" |
| |
| using namespace angle; |
| |
| namespace |
| { |
| enum class ANGLEFeature |
| { |
| Supported, |
| Unsupported, |
| Unknown, |
| }; |
| |
| class VulkanPerformanceCounterTest : public ANGLETest |
| { |
| protected: |
| VulkanPerformanceCounterTest() |
| : mLoadOpNoneSupport(ANGLEFeature::Unknown), |
| mStoreOpNoneSupport(ANGLEFeature::Unknown), |
| mPreferDrawOverClearAttachments(ANGLEFeature::Unknown) |
| { |
| // Depth/Stencil required for SwapShouldInvalidate*. |
| // Also RGBA8 is required to avoid the clear for emulated alpha. |
| setConfigRedBits(8); |
| setConfigGreenBits(8); |
| setConfigBlueBits(8); |
| setConfigAlphaBits(8); |
| setConfigDepthBits(24); |
| setConfigStencilBits(8); |
| } |
| |
| static constexpr GLsizei kOpsTestSize = 16; |
| |
| void initANGLEFeatures() |
| { |
| const bool hasANGLEFeatureControl = |
| IsEGLClientExtensionEnabled("EGL_ANGLE_feature_control"); |
| if (!hasANGLEFeatureControl) |
| { |
| return; |
| } |
| |
| EGLDisplay display = getEGLWindow()->getDisplay(); |
| |
| EGLAttrib featureCount = -1; |
| ASSERT_EQ(static_cast<EGLBoolean>(EGL_TRUE), |
| eglQueryDisplayAttribANGLE(display, EGL_FEATURE_COUNT_ANGLE, &featureCount)); |
| |
| for (EGLAttrib index = 0; index < featureCount; index++) |
| { |
| const char *featureName = eglQueryStringiANGLE(display, EGL_FEATURE_NAME_ANGLE, index); |
| const char *featureStatus = |
| eglQueryStringiANGLE(display, EGL_FEATURE_STATUS_ANGLE, index); |
| ASSERT_NE(featureName, nullptr); |
| ASSERT_NE(featureStatus, nullptr); |
| |
| const bool isStoreOpNone = |
| strcmp(featureName, GetFeatureName(Feature::SupportsRenderPassStoreOpNone)) == 0; |
| const bool isLoadStoreOpNoneEXT = |
| strcmp(featureName, GetFeatureName(Feature::SupportsRenderPassLoadStoreOpNone)) == |
| 0; |
| const bool isEnabled = strcmp(featureStatus, angle::kFeatureStatusEnabled) == 0; |
| const bool isDisabled = strcmp(featureStatus, angle::kFeatureStatusDisabled) == 0; |
| ASSERT_TRUE(isEnabled || isDisabled); |
| const ANGLEFeature isSupported = |
| isEnabled ? ANGLEFeature::Supported : ANGLEFeature::Unsupported; |
| |
| if (isLoadStoreOpNoneEXT) |
| { |
| mLoadOpNoneSupport = isSupported; |
| } |
| |
| if (isStoreOpNone || isLoadStoreOpNoneEXT) |
| { |
| if (mStoreOpNoneSupport == ANGLEFeature::Unknown || |
| mStoreOpNoneSupport == ANGLEFeature::Unsupported) |
| { |
| mStoreOpNoneSupport = isSupported; |
| } |
| } |
| |
| if (strcmp(featureName, |
| GetFeatureName(Feature::PreferDrawClearOverVkCmdClearAttachments)) == 0) |
| { |
| mPreferDrawOverClearAttachments = isSupported; |
| } |
| } |
| |
| // Make sure feature renames are caught |
| ASSERT_NE(mLoadOpNoneSupport, ANGLEFeature::Unknown); |
| ASSERT_NE(mStoreOpNoneSupport, ANGLEFeature::Unknown); |
| ASSERT_NE(mPreferDrawOverClearAttachments, ANGLEFeature::Unknown); |
| |
| // Impossible to have LOAD_OP_NONE but not STORE_OP_NONE |
| ASSERT_FALSE(mLoadOpNoneSupport == ANGLEFeature::Supported && |
| mStoreOpNoneSupport != ANGLEFeature::Supported); |
| } |
| |
| void setupForColorOpsTest(GLFramebuffer *framebuffer, GLTexture *texture) |
| { |
| // Setup the framebuffer |
| glBindFramebuffer(GL_FRAMEBUFFER, *framebuffer); |
| glBindTexture(GL_TEXTURE_2D, *texture); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kOpsTestSize, kOpsTestSize, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, nullptr); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, *texture, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| } |
| |
| void setupForColorDepthOpsTest(GLFramebuffer *framebuffer, |
| GLTexture *texture, |
| GLRenderbuffer *renderbuffer) |
| { |
| // Setup color and depth |
| glBindFramebuffer(GL_FRAMEBUFFER, *framebuffer); |
| glBindTexture(GL_TEXTURE_2D, *texture); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kOpsTestSize, kOpsTestSize, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, nullptr); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, *texture, 0); |
| glBindRenderbuffer(GL_RENDERBUFFER, *renderbuffer); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, kOpsTestSize, kOpsTestSize); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, |
| *renderbuffer); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| // Setup depth parameters |
| glEnable(GL_DEPTH_TEST); |
| glDepthMask(GL_TRUE); |
| glDepthFunc(GL_GEQUAL); |
| glClearDepthf(0.99f); |
| glViewport(0, 0, kOpsTestSize, kOpsTestSize); |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| void setupForDepthStencilOpsTest(GLFramebuffer *framebuffer, |
| GLTexture *texture, |
| GLRenderbuffer *renderbuffer) |
| { |
| // Setup color, depth, and stencil |
| glBindFramebuffer(GL_FRAMEBUFFER, *framebuffer); |
| glBindTexture(GL_TEXTURE_2D, *texture); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kOpsTestSize, kOpsTestSize, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, nullptr); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, *texture, 0); |
| glBindRenderbuffer(GL_RENDERBUFFER, *renderbuffer); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, kOpsTestSize, kOpsTestSize); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, |
| *renderbuffer); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| // Setup depth parameters |
| glEnable(GL_DEPTH_TEST); |
| glDepthMask(GL_TRUE); |
| glDepthFunc(GL_GEQUAL); |
| glEnable(GL_STENCIL_TEST); |
| glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); |
| glStencilMask(0xFF); |
| glClearDepthf(0.99f); |
| glClearStencil(0xAA); |
| glViewport(0, 0, kOpsTestSize, kOpsTestSize); |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| void setupClearAndDrawForDepthStencilOpsTest(GLProgram *program, |
| GLFramebuffer *framebuffer, |
| GLTexture *texture, |
| GLRenderbuffer *renderbuffer, |
| bool clearStencil) |
| { |
| setupForDepthStencilOpsTest(framebuffer, texture, renderbuffer); |
| |
| // Clear and draw with depth and stencil buffer enabled |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | |
| (clearStencil ? GL_STENCIL_BUFFER_BIT : 0)); |
| drawQuad(*program, essl1_shaders::PositionAttrib(), 1.f); |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| void accumulateLoadOpNone(uint32_t loadOpNones, |
| uint32_t *expectedLoadOpNonesOut, |
| uint32_t *expectedLoadOpLoadsOut) |
| { |
| if (mLoadOpNoneSupport == ANGLEFeature::Supported) |
| { |
| *expectedLoadOpNonesOut = loadOpNones; |
| } |
| else |
| { |
| // If LOAD_OP_NONE is not supported, LOAD_OP_LOAD is used instead. |
| *expectedLoadOpLoadsOut += loadOpNones; |
| *expectedLoadOpNonesOut = 0; |
| } |
| } |
| |
| void accumulateStoreOpNone(uint32_t storeOpNones, |
| uint32_t *expectedStoreOpNonesOut, |
| uint32_t *expectedStoreOpStoresOut) |
| { |
| if (mStoreOpNoneSupport == ANGLEFeature::Supported) |
| { |
| *expectedStoreOpNonesOut = storeOpNones; |
| } |
| else |
| { |
| // If STORE_OP_NONE is not supported, STORE_OP_STORE is used instead. |
| *expectedStoreOpStoresOut += storeOpNones; |
| *expectedStoreOpNonesOut = 0; |
| } |
| } |
| |
| void setExpectedCountersForDepthOps(const angle::VulkanPerfCounters &counters, |
| uint32_t incrementalRenderPasses, |
| uint32_t incrementalDepthLoadOpClears, |
| uint32_t incrementalDepthLoadOpLoads, |
| uint32_t incrementalDepthLoadOpNones, |
| uint32_t incrementalDepthStoreOpStores, |
| uint32_t incrementalDepthStoreOpNones, |
| angle::VulkanPerfCounters *expected) |
| { |
| expected->renderPasses = counters.renderPasses + incrementalRenderPasses; |
| expected->depthLoadOpClears = counters.depthLoadOpClears + incrementalDepthLoadOpClears; |
| expected->depthLoadOpLoads = counters.depthLoadOpLoads + incrementalDepthLoadOpLoads; |
| expected->depthStoreOpStores = counters.depthStoreOpStores + incrementalDepthStoreOpStores; |
| |
| accumulateLoadOpNone(counters.depthLoadOpNones + incrementalDepthLoadOpNones, |
| &expected->depthLoadOpNones, &expected->depthLoadOpLoads); |
| accumulateStoreOpNone(counters.depthStoreOpNones + incrementalDepthStoreOpNones, |
| &expected->depthStoreOpNones, &expected->depthStoreOpStores); |
| } |
| |
| void setExpectedCountersForStencilOps(const angle::VulkanPerfCounters &counters, |
| uint32_t incrementalStencilLoadOpClears, |
| uint32_t incrementalStencilLoadOpLoads, |
| uint32_t incrementalStencilLoadOpNones, |
| uint32_t incrementalStencilStoreOpStores, |
| uint32_t incrementalStencilStoreOpNones, |
| angle::VulkanPerfCounters *expected) |
| { |
| expected->stencilLoadOpClears = |
| counters.stencilLoadOpClears + incrementalStencilLoadOpClears; |
| expected->stencilLoadOpLoads = counters.stencilLoadOpLoads + incrementalStencilLoadOpLoads; |
| expected->stencilStoreOpStores = |
| counters.stencilStoreOpStores + incrementalStencilStoreOpStores; |
| |
| accumulateLoadOpNone(counters.stencilLoadOpNones + incrementalStencilLoadOpNones, |
| &expected->stencilLoadOpNones, &expected->stencilLoadOpLoads); |
| accumulateStoreOpNone(counters.stencilStoreOpNones + incrementalStencilStoreOpNones, |
| &expected->stencilStoreOpNones, &expected->stencilStoreOpStores); |
| } |
| |
| void setExpectedCountersForColorOps(const angle::VulkanPerfCounters &counters, |
| uint32_t incrementalRenderPasses, |
| uint32_t incrementalColorLoadOpClears, |
| uint32_t incrementalColorLoadOpLoads, |
| uint32_t incrementalColorLoadOpNones, |
| uint32_t incrementalColorStoreOpStores, |
| uint32_t incrementalColorStoreOpNones, |
| angle::VulkanPerfCounters *expected) |
| { |
| expected->renderPasses = counters.renderPasses + incrementalRenderPasses; |
| expected->colorLoadOpClears = counters.colorLoadOpClears + incrementalColorLoadOpClears; |
| expected->colorLoadOpLoads = counters.colorLoadOpLoads + incrementalColorLoadOpLoads; |
| expected->colorStoreOpStores = counters.colorStoreOpStores + incrementalColorStoreOpStores; |
| |
| accumulateLoadOpNone(counters.colorLoadOpNones + incrementalColorLoadOpNones, |
| &expected->colorLoadOpNones, &expected->colorLoadOpLoads); |
| accumulateStoreOpNone(counters.colorStoreOpNones + incrementalColorStoreOpNones, |
| &expected->colorStoreOpNones, &expected->colorStoreOpStores); |
| } |
| |
| void compareDepthOpCounters(const angle::VulkanPerfCounters &counters, |
| const angle::VulkanPerfCounters &expected) |
| { |
| EXPECT_EQ(expected.depthLoadOpClears, counters.depthLoadOpClears); |
| EXPECT_EQ(expected.depthLoadOpLoads, counters.depthLoadOpLoads); |
| EXPECT_EQ(expected.depthLoadOpNones, counters.depthLoadOpNones); |
| EXPECT_EQ(expected.depthStoreOpStores, counters.depthStoreOpStores); |
| EXPECT_EQ(expected.depthStoreOpNones, counters.depthStoreOpNones); |
| } |
| |
| void compareStencilOpCounters(const angle::VulkanPerfCounters &counters, |
| const angle::VulkanPerfCounters &expected) |
| { |
| EXPECT_EQ(expected.stencilLoadOpClears, counters.stencilLoadOpClears); |
| EXPECT_EQ(expected.stencilLoadOpLoads, counters.stencilLoadOpLoads); |
| EXPECT_EQ(expected.stencilLoadOpNones, counters.stencilLoadOpNones); |
| EXPECT_EQ(expected.stencilStoreOpStores, counters.stencilStoreOpStores); |
| EXPECT_EQ(expected.stencilStoreOpNones, counters.stencilStoreOpNones); |
| } |
| |
| void compareDepthStencilOpCounters(const angle::VulkanPerfCounters &counters, |
| const angle::VulkanPerfCounters &expected) |
| { |
| compareDepthOpCounters(counters, expected); |
| compareStencilOpCounters(counters, expected); |
| } |
| |
| void compareColorOpCounters(const angle::VulkanPerfCounters &counters, |
| const angle::VulkanPerfCounters &expected) |
| { |
| EXPECT_EQ(expected.colorLoadOpClears, counters.colorLoadOpClears); |
| EXPECT_EQ(expected.colorLoadOpLoads, counters.colorLoadOpLoads); |
| EXPECT_EQ(expected.colorLoadOpNones, counters.colorLoadOpNones); |
| EXPECT_EQ(expected.colorStoreOpStores, counters.colorStoreOpStores); |
| EXPECT_EQ(expected.colorStoreOpNones, counters.colorStoreOpNones); |
| } |
| |
| void setAndIncrementDepthStencilLoadCountersForOpsTest( |
| const angle::VulkanPerfCounters &counters, |
| uint32_t incrementalDepthLoadOpLoads, |
| uint32_t incrementalStencilLoadOpLoads, |
| angle::VulkanPerfCounters *expected) |
| { |
| expected->depthLoadOpLoads = counters.depthLoadOpLoads + incrementalDepthLoadOpLoads; |
| expected->stencilLoadOpLoads = counters.stencilLoadOpLoads + incrementalStencilLoadOpLoads; |
| } |
| |
| void compareDepthStencilLoadOpCounters(const angle::VulkanPerfCounters &counters, |
| const angle::VulkanPerfCounters &expected) |
| { |
| EXPECT_EQ(expected.depthLoadOpLoads, counters.depthLoadOpLoads); |
| EXPECT_EQ(expected.stencilLoadOpLoads, counters.stencilLoadOpLoads); |
| } |
| |
| void setExpectedCountersForUnresolveResolveTest(const angle::VulkanPerfCounters &counters, |
| uint32_t incrementalColorAttachmentUnresolves, |
| uint32_t incrementalDepthAttachmentUnresolves, |
| uint32_t incrementalStencilAttachmentUnresolves, |
| uint32_t incrementalColorAttachmentResolves, |
| uint32_t incrementalDepthAttachmentResolves, |
| uint32_t incrementalStencilAttachmentResolves, |
| angle::VulkanPerfCounters *expected) |
| { |
| expected->colorAttachmentUnresolves = |
| counters.colorAttachmentUnresolves + incrementalColorAttachmentUnresolves; |
| expected->depthAttachmentUnresolves = |
| counters.depthAttachmentUnresolves + incrementalDepthAttachmentUnresolves; |
| expected->stencilAttachmentUnresolves = |
| counters.stencilAttachmentUnresolves + incrementalStencilAttachmentUnresolves; |
| expected->colorAttachmentResolves = |
| counters.colorAttachmentResolves + incrementalColorAttachmentResolves; |
| expected->depthAttachmentResolves = |
| counters.depthAttachmentResolves + incrementalDepthAttachmentResolves; |
| expected->stencilAttachmentResolves = |
| counters.stencilAttachmentResolves + incrementalStencilAttachmentResolves; |
| } |
| |
| void compareCountersForUnresolveResolveTest(const angle::VulkanPerfCounters &counters, |
| const angle::VulkanPerfCounters &expected) |
| { |
| EXPECT_EQ(expected.colorAttachmentUnresolves, counters.colorAttachmentUnresolves); |
| EXPECT_EQ(expected.depthAttachmentUnresolves, counters.depthAttachmentUnresolves); |
| if (counters.stencilAttachmentUnresolves != 0) |
| { |
| // Allow stencil unresolves to be 0. If VK_EXT_shader_stencil_export is not supported, |
| // stencil unresolve is impossible. |
| EXPECT_EQ(expected.stencilAttachmentUnresolves, counters.stencilAttachmentUnresolves); |
| } |
| EXPECT_EQ(expected.colorAttachmentResolves, counters.colorAttachmentResolves); |
| EXPECT_EQ(expected.depthAttachmentResolves, counters.depthAttachmentResolves); |
| EXPECT_EQ(expected.stencilAttachmentResolves, counters.stencilAttachmentResolves); |
| } |
| |
| void compareClearAttachmentsCounter(uint32_t expected, uint32_t actual) |
| { |
| if (mPreferDrawOverClearAttachments == ANGLEFeature::Supported) |
| { |
| EXPECT_EQ(actual, 0u); |
| } |
| else |
| { |
| EXPECT_EQ(actual, expected); |
| } |
| } |
| |
| void maskedFramebufferFetchDraw(const GLColor &clearColor, GLBuffer &buffer); |
| void maskedFramebufferFetchDrawVerify(const GLColor &expectedColor, GLBuffer &buffer); |
| |
| angle::VulkanPerfCounters getPerfCounters() |
| { |
| if (mIndexMap.empty()) |
| { |
| mIndexMap = BuildCounterNameToIndexMap(); |
| } |
| |
| return GetPerfCounters(mIndexMap); |
| } |
| |
| CounterNameToIndexMap mIndexMap; |
| |
| // Support status for ANGLE features. |
| ANGLEFeature mLoadOpNoneSupport; |
| ANGLEFeature mStoreOpNoneSupport; |
| ANGLEFeature mPreferDrawOverClearAttachments; |
| }; |
| |
| class VulkanPerformanceCounterTest_ES31 : public VulkanPerformanceCounterTest |
| {}; |
| |
| class VulkanPerformanceCounterTest_MSAA : public VulkanPerformanceCounterTest |
| { |
| protected: |
| VulkanPerformanceCounterTest_MSAA() : VulkanPerformanceCounterTest() |
| { |
| setSamples(4); |
| setMultisampleEnabled(true); |
| } |
| }; |
| |
| class VulkanPerformanceCounterTest_SingleBuffer : public VulkanPerformanceCounterTest |
| { |
| protected: |
| VulkanPerformanceCounterTest_SingleBuffer() : VulkanPerformanceCounterTest() |
| { |
| setMutableRenderBuffer(true); |
| } |
| }; |
| |
| void VulkanPerformanceCounterTest::maskedFramebufferFetchDraw(const GLColor &clearColor, |
| GLBuffer &buffer) |
| { |
| // Initialize the color buffer |
| angle::Vector4 clearAsVec4 = clearColor.toNormalizedVector(); |
| glClearColor(clearAsVec4[0], clearAsVec4[1], clearAsVec4[2], clearAsVec4[3]); |
| glClear(GL_COLOR_BUFFER_BIT); |
| EXPECT_PIXEL_COLOR_NEAR(0, 0, clearColor, 1); |
| |
| // Create output buffer |
| constexpr GLsizei kBufferSize = kOpsTestSize * kOpsTestSize * sizeof(float[4]); |
| glBindBuffer(GL_SHADER_STORAGE_BUFFER, buffer); |
| glBufferData(GL_SHADER_STORAGE_BUFFER, kBufferSize, nullptr, GL_STATIC_DRAW); |
| glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 0, buffer, 0, kBufferSize); |
| |
| // Zero-initialize it |
| void *bufferData = glMapBufferRange( |
| GL_SHADER_STORAGE_BUFFER, 0, kBufferSize, |
| GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT); |
| memset(bufferData, 0, kBufferSize); |
| glUnmapBuffer(GL_SHADER_STORAGE_BUFFER); |
| |
| // Mask color output |
| glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); |
| |
| static constexpr char kVS[] = R"(#version 310 es |
| in highp vec4 a_position; |
| |
| void main (void) |
| { |
| gl_Position = a_position; |
| })"; |
| |
| static constexpr char kFS[] = R"(#version 310 es |
| #extension GL_EXT_shader_framebuffer_fetch_non_coherent : require |
| layout(noncoherent, location = 0) inout highp vec4 o_color; |
| |
| layout(std140, binding = 0) buffer outBlock { |
| highp vec4 data[256]; |
| }; |
| |
| uniform highp vec4 u_color; |
| void main (void) |
| { |
| uint index = uint(gl_FragCoord.y) * 16u + uint(gl_FragCoord.x); |
| data[index] = o_color; |
| o_color += u_color; |
| })"; |
| |
| // Draw |
| ANGLE_GL_PROGRAM(program, kVS, kFS); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| void VulkanPerformanceCounterTest::maskedFramebufferFetchDrawVerify(const GLColor &expectedColor, |
| GLBuffer &buffer) |
| { |
| angle::Vector4 expectedAsVec4 = expectedColor.toNormalizedVector(); |
| |
| // Read back the storage buffer and make sure framebuffer fetch worked as intended despite |
| // masked color. |
| glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT); |
| |
| constexpr GLsizei kBufferSize = kOpsTestSize * kOpsTestSize * sizeof(float[4]); |
| const float *colorData = static_cast<const float *>( |
| glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kBufferSize, GL_MAP_READ_BIT)); |
| for (uint32_t y = 0; y < kOpsTestSize; ++y) |
| { |
| for (uint32_t x = 0; x < kOpsTestSize; ++x) |
| { |
| uint32_t ssboIndex = (y * kOpsTestSize + x) * 4; |
| EXPECT_NEAR(colorData[ssboIndex + 0], expectedAsVec4[0], 0.05); |
| EXPECT_NEAR(colorData[ssboIndex + 1], expectedAsVec4[1], 0.05); |
| EXPECT_NEAR(colorData[ssboIndex + 2], expectedAsVec4[2], 0.05); |
| EXPECT_NEAR(colorData[ssboIndex + 3], expectedAsVec4[3], 0.05); |
| } |
| } |
| glUnmapBuffer(GL_SHADER_STORAGE_BUFFER); |
| } |
| |
| // Tests that texture updates to unused textures don't break the RP. |
| TEST_P(VulkanPerformanceCounterTest, NewTextureDoesNotBreakRenderPass) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| GLColor kInitialData[4] = {GLColor::red, GLColor::blue, GLColor::green, GLColor::yellow}; |
| |
| // Step 1: Set up a simple 2D Texture rendering loop. |
| GLTexture texture; |
| glBindTexture(GL_TEXTURE_2D, texture); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, kInitialData); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| |
| auto quadVerts = GetQuadVertices(); |
| |
| GLBuffer vertexBuffer; |
| glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); |
| glBufferData(GL_ARRAY_BUFFER, quadVerts.size() * sizeof(quadVerts[0]), quadVerts.data(), |
| GL_STATIC_DRAW); |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D()); |
| glUseProgram(program); |
| |
| GLint posLoc = glGetAttribLocation(program, essl1_shaders::PositionAttrib()); |
| ASSERT_NE(-1, posLoc); |
| |
| glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr); |
| glEnableVertexAttribArray(posLoc); |
| ASSERT_GL_NO_ERROR(); |
| |
| glDrawArrays(GL_TRIANGLES, 0, 6); |
| ASSERT_GL_NO_ERROR(); |
| |
| uint32_t expectedRenderPassCount = getPerfCounters().renderPasses; |
| |
| // Step 2: Introduce a new 2D Texture with the same Program and Framebuffer. |
| GLTexture newTexture; |
| glBindTexture(GL_TEXTURE_2D, newTexture); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, kInitialData); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| |
| glDrawArrays(GL_TRIANGLES, 0, 6); |
| ASSERT_GL_NO_ERROR(); |
| |
| uint32_t actualRenderPassCount = getPerfCounters().renderPasses; |
| EXPECT_EQ(expectedRenderPassCount, actualRenderPassCount); |
| } |
| |
| // Tests that submitting the outside command buffer due to texture upload size does not break the |
| // current render pass. |
| TEST_P(VulkanPerformanceCounterTest, SubmittingOutsideCommandBufferDoesNotBreakRenderPass) |
| { |
| initANGLEFeatures(); |
| // http://anglebug.com/6354 |
| |
| size_t kMaxBufferToImageCopySize = 1 << 28; |
| uint32_t kNumSubmits = 2; |
| uint32_t expectedRenderPassCount = getPerfCounters().renderPasses + 1; |
| uint32_t expectedSubmitCommandsCount = getPerfCounters().vkQueueSubmitCallsTotal + kNumSubmits; |
| |
| // Step 1: Set up a simple 2D texture. |
| GLTexture texture; |
| GLsizei texDim = 256; |
| uint32_t pixelSizeRGBA = 4; |
| uint32_t textureSize = texDim * texDim * pixelSizeRGBA; |
| std::vector<GLColor> kInitialData(texDim * texDim, GLColor::green); |
| |
| glBindTexture(GL_TEXTURE_2D, texture); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texDim, texDim, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| kInitialData.data()); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| |
| auto quadVerts = GetQuadVertices(); |
| |
| GLBuffer vertexBuffer; |
| glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); |
| glBufferData(GL_ARRAY_BUFFER, quadVerts.size() * sizeof(quadVerts[0]), quadVerts.data(), |
| GL_STATIC_DRAW); |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D()); |
| glUseProgram(program); |
| |
| GLint posLoc = glGetAttribLocation(program, essl1_shaders::PositionAttrib()); |
| ASSERT_NE(-1, posLoc); |
| |
| glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr); |
| glEnableVertexAttribArray(posLoc); |
| ASSERT_GL_NO_ERROR(); |
| |
| glDrawArrays(GL_TRIANGLES, 0, 6); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Step 2: Load a new 2D Texture multiple times with the same Program and Framebuffer. The total |
| // size of the loaded textures must exceed the threshold to submit the outside command buffer. |
| auto maxLoadCount = |
| static_cast<size_t>((kMaxBufferToImageCopySize / textureSize) * kNumSubmits + 1); |
| for (size_t loadCount = 0; loadCount < maxLoadCount; loadCount++) |
| { |
| GLTexture newTexture; |
| glBindTexture(GL_TEXTURE_2D, newTexture); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texDim, texDim, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| kInitialData.data()); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| |
| glDrawArrays(GL_TRIANGLES, 0, 6); |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| // Verify render pass and submitted frame counts. |
| EXPECT_EQ(getPerfCounters().renderPasses, expectedRenderPassCount); |
| EXPECT_EQ(getPerfCounters().vkQueueSubmitCallsTotal, expectedSubmitCommandsCount); |
| } |
| |
| // Tests that RGB texture should not break renderpass. |
| TEST_P(VulkanPerformanceCounterTest, SampleFromRGBTextureDoesNotBreakRenderPass) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D()); |
| glUseProgram(program); |
| GLint textureLoc = glGetUniformLocation(program, essl1_shaders::Texture2DUniform()); |
| ASSERT_NE(-1, textureLoc); |
| |
| GLTexture textureRGBA; |
| glActiveTexture(GL_TEXTURE0); |
| glBindTexture(GL_TEXTURE_2D, textureRGBA); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
| |
| GLTexture textureRGB; |
| glActiveTexture(GL_TEXTURE1); |
| glBindTexture(GL_TEXTURE_2D, textureRGB); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
| |
| uint32_t expectedRenderPassCount = getPerfCounters().renderPasses + 1; |
| |
| // First draw with textureRGBA which should start the renderpass |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
| glUniform1i(textureLoc, 0); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Next draw with textureRGB which should not end the renderpass |
| glUniform1i(textureLoc, 1); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| |
| uint32_t actualRenderPassCount = getPerfCounters().renderPasses; |
| EXPECT_EQ(expectedRenderPassCount, actualRenderPassCount); |
| } |
| |
| // Tests that RGB texture should not break renderpass. |
| TEST_P(VulkanPerformanceCounterTest, RenderToRGBTextureDoesNotBreakRenderPass) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Passthrough(), essl1_shaders::fs::UniformColor()); |
| glUseProgram(program); |
| GLint colorUniformLocation = |
| glGetUniformLocation(program, angle::essl1_shaders::ColorUniform()); |
| ASSERT_NE(-1, colorUniformLocation); |
| ASSERT_GL_NO_ERROR(); |
| |
| GLTexture textureRGB; |
| glActiveTexture(GL_TEXTURE1); |
| glBindTexture(GL_TEXTURE_2D, textureRGB); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 256, 256, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
| |
| GLFramebuffer framebuffer; |
| glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureRGB, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| ASSERT_GL_NO_ERROR(); |
| |
| uint32_t expectedRenderPassCount = getPerfCounters().renderPasses + 1; |
| |
| // Draw into FBO |
| glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); |
| glClearColor(0.0f, 1.0f, 0.0f, 1.0f); // clear to green |
| glClear(GL_COLOR_BUFFER_BIT); |
| glViewport(0, 0, 256, 256); |
| glUniform4fv(colorUniformLocation, 1, GLColor::blue.toNormalizedVector().data()); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| |
| uint32_t actualRenderPassCount = getPerfCounters().renderPasses; |
| EXPECT_EQ(expectedRenderPassCount, actualRenderPassCount); |
| } |
| |
| // Tests that changing a Texture's max level hits the descriptor set cache. |
| TEST_P(VulkanPerformanceCounterTest, ChangingMaxLevelHitsDescriptorCache) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| GLColor kInitialData[4] = {GLColor::red, GLColor::blue, GLColor::green, GLColor::yellow}; |
| |
| // Step 1: Set up a simple mipped 2D Texture rendering loop. |
| GLTexture texture; |
| glBindTexture(GL_TEXTURE_2D, texture); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, kInitialData); |
| glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, kInitialData); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1); |
| |
| auto quadVerts = GetQuadVertices(); |
| |
| GLBuffer vertexBuffer; |
| glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); |
| glBufferData(GL_ARRAY_BUFFER, quadVerts.size() * sizeof(quadVerts[0]), quadVerts.data(), |
| GL_STATIC_DRAW); |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D()); |
| glUseProgram(program); |
| |
| GLint posLoc = glGetAttribLocation(program, essl1_shaders::PositionAttrib()); |
| ASSERT_NE(-1, posLoc); |
| |
| glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr); |
| glEnableVertexAttribArray(posLoc); |
| ASSERT_GL_NO_ERROR(); |
| |
| glDrawArrays(GL_TRIANGLES, 0, 6); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Step 2: Change max level and draw. |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); |
| glDrawArrays(GL_TRIANGLES, 0, 6); |
| ASSERT_GL_NO_ERROR(); |
| |
| uint32_t expectedWriteDescriptorSetCount = getPerfCounters().writeDescriptorSets; |
| |
| // Step 3: Change max level back to original value and verify we hit the cache. |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1); |
| glDrawArrays(GL_TRIANGLES, 0, 6); |
| ASSERT_GL_NO_ERROR(); |
| |
| uint32_t actualWriteDescriptorSetCount = getPerfCounters().writeDescriptorSets; |
| EXPECT_EQ(expectedWriteDescriptorSetCount, actualWriteDescriptorSetCount); |
| } |
| |
| // Tests that two glCopyBufferSubData commands can share a barrier. |
| TEST_P(VulkanPerformanceCounterTest, IndependentBufferCopiesShareSingleBarrier) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| constexpr GLint srcDataA[] = {1, 2, 3, 4}; |
| constexpr GLint srcDataB[] = {5, 6, 7, 8}; |
| |
| // Step 1: Set up four buffers for two copies. |
| GLBuffer srcA; |
| glBindBuffer(GL_COPY_READ_BUFFER, srcA); |
| // Note: We can't use GL_STATIC_COPY. Using STATIC will cause driver to allocate a host |
| // invisible memory and issue a copyToBuffer, which will trigger outsideRenderPassCommandBuffer |
| // flush when glCopyBufferSubData is called due to read after write. That will break the |
| // expectations and cause test to fail. |
| glBufferData(GL_COPY_READ_BUFFER, sizeof(srcDataA), srcDataA, GL_DYNAMIC_COPY); |
| |
| GLBuffer dstA; |
| glBindBuffer(GL_COPY_WRITE_BUFFER, dstA); |
| // Note: We can't use GL_STATIC_COPY. Using STATIC will cause driver to allocate a host |
| // invisible memory and issue a copyToBuffer, which will trigger outsideRenderPassCommandBuffer |
| // flush when glCopyBufferSubData is called due to write after write. That will break the |
| // expectations and cause test to fail. |
| glBufferData(GL_COPY_WRITE_BUFFER, sizeof(srcDataA[0]) * 2, nullptr, GL_DYNAMIC_COPY); |
| |
| GLBuffer srcB; |
| glBindBuffer(GL_COPY_READ_BUFFER, srcB); |
| glBufferData(GL_COPY_READ_BUFFER, sizeof(srcDataB), srcDataB, GL_DYNAMIC_COPY); |
| |
| GLBuffer dstB; |
| glBindBuffer(GL_COPY_WRITE_BUFFER, dstB); |
| glBufferData(GL_COPY_WRITE_BUFFER, sizeof(srcDataB[0]) * 2, nullptr, GL_DYNAMIC_COPY); |
| |
| // We expect that ANGLE generate zero additional command buffers. |
| uint32_t expectedFlushCount = getPerfCounters().flushedOutsideRenderPassCommandBuffers; |
| |
| // Step 2: Do the two copies. |
| glBindBuffer(GL_COPY_READ_BUFFER, srcA); |
| glBindBuffer(GL_COPY_WRITE_BUFFER, dstA); |
| glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, sizeof(srcDataB[0]), 0, |
| sizeof(srcDataA[0]) * 2); |
| |
| glBindBuffer(GL_COPY_READ_BUFFER, srcB); |
| glBindBuffer(GL_COPY_WRITE_BUFFER, dstB); |
| glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, sizeof(srcDataB[0]), 0, |
| sizeof(srcDataB[0]) * 2); |
| |
| ASSERT_GL_NO_ERROR(); |
| |
| uint32_t actualFlushCount = getPerfCounters().flushedOutsideRenderPassCommandBuffers; |
| EXPECT_EQ(expectedFlushCount, actualFlushCount); |
| } |
| |
| // Test resolving a multisampled texture with blit doesn't break the render pass so a subpass can be |
| // used |
| TEST_P(VulkanPerformanceCounterTest_ES31, MultisampleResolveWithBlit) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| constexpr int kSize = 16; |
| glViewport(0, 0, kSize, kSize); |
| |
| GLFramebuffer msaaFBO; |
| glBindFramebuffer(GL_FRAMEBUFFER, msaaFBO.get()); |
| |
| GLTexture texture; |
| glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, texture.get()); |
| glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA8, kSize, kSize, false); |
| ASSERT_GL_NO_ERROR(); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, |
| texture.get(), 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| ANGLE_GL_PROGRAM(gradientProgram, essl31_shaders::vs::Passthrough(), |
| essl31_shaders::fs::RedGreenGradient()); |
| drawQuad(gradientProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Create another FBO to resolve the multisample buffer into. |
| GLTexture resolveTexture; |
| GLFramebuffer resolveFBO; |
| glBindTexture(GL_TEXTURE_2D, resolveTexture); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| glBindFramebuffer(GL_FRAMEBUFFER, resolveFBO); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, resolveTexture, 0); |
| EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER)); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, msaaFBO); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolveFBO); |
| glBlitFramebuffer(0, 0, kSize, kSize, 0, 0, kSize, kSize, GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| ASSERT_GL_NO_ERROR(); |
| |
| EXPECT_EQ(getPerfCounters().resolveImageCommands, 0u); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, resolveFBO); |
| constexpr uint8_t kHalfPixelGradient = 256 / kSize / 2; |
| EXPECT_PIXEL_NEAR(0, 0, kHalfPixelGradient, kHalfPixelGradient, 0, 255, 1.0); |
| EXPECT_PIXEL_NEAR(kSize - 1, 0, 255 - kHalfPixelGradient, kHalfPixelGradient, 0, 255, 1.0); |
| EXPECT_PIXEL_NEAR(0, kSize - 1, kHalfPixelGradient, 255 - kHalfPixelGradient, 0, 255, 1.0); |
| EXPECT_PIXEL_NEAR(kSize - 1, kSize - 1, 255 - kHalfPixelGradient, 255 - kHalfPixelGradient, 0, |
| 255, 1.0); |
| } |
| |
| // Ensures a read-only depth-stencil feedback loop works in a single RenderPass. |
| TEST_P(VulkanPerformanceCounterTest, ReadOnlyDepthStencilFeedbackLoopUsesSingleRenderPass) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| constexpr GLsizei kSize = 4; |
| |
| ANGLE_GL_PROGRAM(redProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); |
| ANGLE_GL_PROGRAM(texProgram, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D()); |
| |
| GLTexture colorTexture; |
| glBindTexture(GL_TEXTURE_2D, colorTexture); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| |
| setupQuadVertexBuffer(0.5f, 1.0f); |
| glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); |
| glEnableVertexAttribArray(0); |
| |
| // Set up a depth texture and fill it with an arbitrary initial value. |
| GLTexture depthTexture; |
| glBindTexture(GL_TEXTURE_2D, depthTexture); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, kSize, kSize, 0, GL_DEPTH_COMPONENT, |
| GL_UNSIGNED_INT, nullptr); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| glBindTexture(GL_TEXTURE_2D, 0); |
| |
| GLFramebuffer depthAndColorFBO; |
| glBindFramebuffer(GL_FRAMEBUFFER, depthAndColorFBO); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture, 0); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTexture, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| GLFramebuffer depthOnlyFBO; |
| glBindFramebuffer(GL_FRAMEBUFFER, depthOnlyFBO); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTexture, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| // Draw to a first FBO to initialize the depth buffer. |
| glBindFramebuffer(GL_FRAMEBUFFER, depthOnlyFBO); |
| glEnable(GL_DEPTH_TEST); |
| glUseProgram(redProgram); |
| glDrawArrays(GL_TRIANGLES, 0, 6); |
| ASSERT_GL_NO_ERROR(); |
| |
| uint32_t expectedRenderPassCount = getPerfCounters().renderPasses + 1; |
| |
| // Start new RenderPass with depth write disabled and no loop. |
| glBindFramebuffer(GL_FRAMEBUFFER, depthAndColorFBO); |
| glDepthMask(false); |
| glDrawArrays(GL_TRIANGLES, 0, 6); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Now set up the read-only feedback loop. |
| glBindTexture(GL_TEXTURE_2D, depthTexture); |
| glUseProgram(texProgram); |
| glDrawArrays(GL_TRIANGLES, 0, 6); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Tweak the bits to keep it read-only. |
| glEnable(GL_DEPTH_TEST); |
| glDrawArrays(GL_TRIANGLES, 0, 6); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Render with just the depth attachment. |
| glUseProgram(redProgram); |
| glBindTexture(GL_TEXTURE_2D, 0); |
| glDrawArrays(GL_TRIANGLES, 0, 6); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Rebind the depth texture. |
| glUseProgram(texProgram); |
| glDepthMask(GL_FALSE); |
| glEnable(GL_DEPTH_TEST); |
| glBindTexture(GL_TEXTURE_2D, depthTexture); |
| glDrawArrays(GL_TRIANGLES, 0, 6); |
| ASSERT_GL_NO_ERROR(); |
| |
| uint32_t actualRenderPassCount = getPerfCounters().renderPasses; |
| EXPECT_EQ(expectedRenderPassCount, actualRenderPassCount); |
| |
| // Do a final write to depth to make sure we can switch out of read-only mode. |
| glBindTexture(GL_TEXTURE_2D, 0); |
| glDepthMask(GL_TRUE); |
| glDrawArrays(GL_TRIANGLES, 0, 6); |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| // Tests that invalidate followed by masked draws results in no load and store. |
| // |
| // - Scenario: invalidate, mask color, draw |
| TEST_P(VulkanPerformanceCounterTest, ColorInvalidateMaskDraw) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| angle::VulkanPerfCounters expected; |
| |
| // Expect rpCount+1, color(Clears+0, Loads+0, LoadNones+0, Stores+0, StoreNones+0) |
| setExpectedCountersForColorOps(getPerfCounters(), 1, 0, 0, 0, 0, 0, &expected); |
| |
| GLFramebuffer framebuffer; |
| GLTexture texture; |
| setupForColorOpsTest(&framebuffer, &texture); |
| |
| // Invalidate |
| const GLenum discards[] = {GL_COLOR_ATTACHMENT0}; |
| glInvalidateFramebuffer(GL_FRAMEBUFFER, 1, discards); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Mask color output |
| glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); |
| |
| // Draw |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| |
| EXPECT_EQ(expected.renderPasses, getPerfCounters().renderPasses); |
| |
| // Use swapBuffers and then check how many loads and stores were actually done |
| swapBuffers(); |
| compareColorOpCounters(getPerfCounters(), expected); |
| |
| // Start and end another render pass without color mask |
| ++expected.renderPasses; |
| ++expected.colorStoreOpStores; |
| |
| glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| |
| compareColorOpCounters(getPerfCounters(), expected); |
| } |
| |
| // Tests that invalidate followed by discarded draws results in no load and store. |
| // |
| // - Scenario: invalidate, rasterizer discard, draw |
| TEST_P(VulkanPerformanceCounterTest, ColorInvalidateDiscardDraw) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| angle::VulkanPerfCounters expected; |
| |
| // Expect rpCount+1, color(Clears+0, Loads+0, LoadNones+0, Stores+0, StoreNones+0) |
| setExpectedCountersForColorOps(getPerfCounters(), 1, 0, 0, 0, 0, 0, &expected); |
| |
| GLFramebuffer framebuffer; |
| GLTexture texture; |
| setupForColorOpsTest(&framebuffer, &texture); |
| |
| // Invalidate |
| const GLenum discards[] = {GL_COLOR_ATTACHMENT0}; |
| glInvalidateFramebuffer(GL_FRAMEBUFFER, 1, discards); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Mask color output |
| glEnable(GL_RASTERIZER_DISCARD); |
| |
| // Draw |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| |
| EXPECT_EQ(expected.renderPasses, getPerfCounters().renderPasses); |
| |
| // Use swapBuffers and then check how many loads and stores were actually done |
| swapBuffers(); |
| compareColorOpCounters(getPerfCounters(), expected); |
| |
| // Start and end another render pass without color mask |
| ++expected.renderPasses; |
| ++expected.colorStoreOpStores; |
| |
| glDisable(GL_RASTERIZER_DISCARD); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| |
| compareColorOpCounters(getPerfCounters(), expected); |
| } |
| |
| // Tests that masked draws results in no load and store. |
| // |
| // - Scenario: mask color, draw |
| TEST_P(VulkanPerformanceCounterTest, ColorMaskedDraw) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| angle::VulkanPerfCounters expected; |
| |
| // Expect rpCount+1, color(Clears+0, Loads+0, LoadNones+1, Stores+0, StoreNones+1) |
| setExpectedCountersForColorOps(getPerfCounters(), 1, 0, 0, 1, 0, 1, &expected); |
| |
| GLFramebuffer framebuffer; |
| GLTexture texture; |
| setupForColorOpsTest(&framebuffer, &texture); |
| |
| // Initialize the color buffer |
| glClearColor(1, 0, 0, 1); |
| glClear(GL_COLOR_BUFFER_BIT); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| |
| // Mask color output |
| glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); |
| |
| // Draw |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green()); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| |
| EXPECT_EQ(expected.renderPasses, getPerfCounters().renderPasses); |
| |
| // Break the render pass and check how many loads and stores were actually done |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| compareColorOpCounters(getPerfCounters(), expected); |
| |
| // Start and end another render pass without color mask |
| ++expected.renderPasses; |
| ++expected.colorLoadOpLoads; |
| ++expected.colorStoreOpStores; |
| |
| glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| |
| compareColorOpCounters(getPerfCounters(), expected); |
| } |
| |
| // Tests that discarded draws results in no load and store. |
| // |
| // - Scenario: rasterizer discard, draw |
| TEST_P(VulkanPerformanceCounterTest, ColorDiscardDraw) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| angle::VulkanPerfCounters expected; |
| |
| // Expect rpCount+1, color(Clears+0, Loads+0, LoadNones+1, Stores+0, StoreNones+1) |
| setExpectedCountersForColorOps(getPerfCounters(), 1, 0, 0, 1, 0, 1, &expected); |
| |
| GLFramebuffer framebuffer; |
| GLTexture texture; |
| setupForColorOpsTest(&framebuffer, &texture); |
| |
| // Initialize the color buffer |
| glClearColor(1, 0, 0, 1); |
| glClear(GL_COLOR_BUFFER_BIT); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| |
| // Mask color output |
| glEnable(GL_RASTERIZER_DISCARD); |
| |
| // Draw |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green()); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| |
| EXPECT_EQ(expected.renderPasses, getPerfCounters().renderPasses); |
| |
| // Break the render pass and check how many loads and stores were actually done |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| compareColorOpCounters(getPerfCounters(), expected); |
| |
| // Start and end another render pass without color mask |
| ++expected.renderPasses; |
| ++expected.colorLoadOpLoads; |
| ++expected.colorStoreOpStores; |
| |
| glDisable(GL_RASTERIZER_DISCARD); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| |
| compareColorOpCounters(getPerfCounters(), expected); |
| } |
| |
| // Test that read-only color usage results in load but no store. |
| // |
| // - Scenario: mask color, framebuffer fetch draw |
| TEST_P(VulkanPerformanceCounterTest_ES31, ColorMaskedFramebufferFetchDraw) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch_non_coherent")); |
| initANGLEFeatures(); |
| |
| angle::VulkanPerfCounters expected; |
| |
| // Expect rpCount+1, color(Clears+0, Loads+1, LoadNones+0, Stores+0, StoreNones+1) |
| setExpectedCountersForColorOps(getPerfCounters(), 1, 0, 1, 0, 0, 1, &expected); |
| |
| GLFramebuffer framebuffer; |
| GLTexture texture; |
| setupForColorOpsTest(&framebuffer, &texture); |
| |
| GLBuffer buffer; |
| const GLColor kClearColor(40, 70, 100, 150); |
| maskedFramebufferFetchDraw(kClearColor, buffer); |
| |
| EXPECT_EQ(expected.renderPasses, getPerfCounters().renderPasses); |
| |
| // Break the render pass and check how many loads and stores were actually done |
| EXPECT_PIXEL_COLOR_NEAR(0, 0, kClearColor, 1); |
| |
| maskedFramebufferFetchDrawVerify(kClearColor, buffer); |
| compareColorOpCounters(getPerfCounters(), expected); |
| } |
| |
| // Tests that clear after masked draws is optimized to use loadOp |
| // |
| // - Scenario: clear, mask color, draw, clear |
| TEST_P(VulkanPerformanceCounterTest, ColorClearMaskedDrawThenClear) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| angle::VulkanPerfCounters expected; |
| |
| // Expect rpCount+1, color(Clears+1, Loads+0, LoadNones+0, Stores+1, StoreNones+0) |
| // No vkCmdClearAttachments should be issued. |
| setExpectedCountersForColorOps(getPerfCounters(), 1, 1, 0, 0, 1, 0, &expected); |
| expected.colorClearAttachments = getPerfCounters().colorClearAttachments; |
| |
| GLFramebuffer framebuffer; |
| GLTexture texture; |
| setupForColorOpsTest(&framebuffer, &texture); |
| |
| // Clear color first |
| glClearColor(1, 0, 0, 1); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| // Mask color output |
| glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); |
| |
| // Draw |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green()); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Then clear color again. This clear is moved up to loadOp, overriding the initial clear. |
| glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); |
| glClearColor(0, 0, 1, 1); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| EXPECT_EQ(expected.renderPasses, getPerfCounters().renderPasses); |
| |
| // Break the render pass and check how many loads and stores were actually done |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue); |
| compareColorOpCounters(getPerfCounters(), expected); |
| compareClearAttachmentsCounter(expected.colorClearAttachments, |
| getPerfCounters().colorClearAttachments); |
| } |
| |
| // Test that clear of read-only color is not reordered with the draw. |
| // |
| // - Scenario: mask color, framebuffer fetch draw, clear |
| TEST_P(VulkanPerformanceCounterTest_ES31, ColorMaskedFramebufferFetchDrawThenClear) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch_non_coherent")); |
| initANGLEFeatures(); |
| |
| angle::VulkanPerfCounters expected; |
| |
| // Expect rpCount+1, color(Clears+0, Loads+1, LoadNones+0, Stores+1, StoreNones+0) |
| // vkCmdClearAttachments should be used for the second clear. |
| setExpectedCountersForColorOps(getPerfCounters(), 1, 0, 1, 0, 1, 0, &expected); |
| expected.colorClearAttachments = getPerfCounters().colorClearAttachments + 1; |
| |
| GLFramebuffer framebuffer; |
| GLTexture texture; |
| setupForColorOpsTest(&framebuffer, &texture); |
| |
| GLBuffer buffer; |
| const GLColor kClearColor(40, 70, 100, 150); |
| maskedFramebufferFetchDraw(kClearColor, buffer); |
| |
| glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); |
| glClearColor(1, 0, 0, 1); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| EXPECT_EQ(expected.renderPasses, getPerfCounters().renderPasses); |
| |
| // Break the render pass and check how many loads and stores were actually done |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| |
| maskedFramebufferFetchDrawVerify(kClearColor, buffer); |
| compareColorOpCounters(getPerfCounters(), expected); |
| compareClearAttachmentsCounter(expected.colorClearAttachments, |
| getPerfCounters().colorClearAttachments); |
| } |
| |
| // Tests that clear after unused depth/stencil is optimized to use loadOp |
| // |
| // - Scenario: disable depth/stencil, draw, clear |
| TEST_P(VulkanPerformanceCounterTest, DepthStencilMaskedDrawThenClear) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| // This optimization is not implemented when this workaround is in effect. |
| ANGLE_SKIP_TEST_IF(mPreferDrawOverClearAttachments == ANGLEFeature::Supported); |
| |
| angle::VulkanPerfCounters expected; |
| |
| // Expect rpCount+1, depth(Clears+1, Loads+0, LoadNones+0, Stores+1, StoreNones+0), |
| // stencil(Clears+1, Loads+0, LoadNones+0, Stores+1, StoreNones+0) |
| setExpectedCountersForDepthOps(getPerfCounters(), 1, 1, 0, 0, 1, 0, &expected); |
| setExpectedCountersForStencilOps(getPerfCounters(), 1, 0, 0, 1, 0, &expected); |
| |
| // No vkCmdClearAttachments should be issued. |
| expected.depthClearAttachments = getPerfCounters().depthClearAttachments; |
| expected.stencilClearAttachments = getPerfCounters().stencilClearAttachments; |
| |
| GLFramebuffer framebuffer; |
| GLTexture texture; |
| GLRenderbuffer renderbuffer; |
| setupForDepthStencilOpsTest(&framebuffer, &texture, &renderbuffer); |
| |
| // Disable depth/stencil |
| glDisable(GL_DEPTH_TEST); |
| glDisable(GL_STENCIL_TEST); |
| |
| // Issue a draw call |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green()); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| |
| // Clear depth/stencil |
| glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| EXPECT_EQ(expected.renderPasses, getPerfCounters().renderPasses); |
| |
| // Break the render pass and check how many loads and stores were actually done |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| compareDepthStencilOpCounters(getPerfCounters(), expected); |
| compareClearAttachmentsCounter(expected.depthClearAttachments, |
| getPerfCounters().depthClearAttachments); |
| compareClearAttachmentsCounter(expected.stencilClearAttachments, |
| getPerfCounters().depthClearAttachments); |
| } |
| |
| // Tests that common PUBG MOBILE case does not break render pass, and that counts are correct: |
| // |
| // - Scenario: invalidate, disable, draw |
| TEST_P(VulkanPerformanceCounterTest, DepthStencilInvalidateDisableDraw) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| angle::VulkanPerfCounters expected; |
| |
| // Expect rpCount+1, depth(Clears+1, Loads+0, LoadNones+0, Stores+0, StoreNones+0), |
| // stencil(Clears+0, Loads+0, LoadNones+0, Stores+0, StoreNones+0) |
| setExpectedCountersForDepthOps(getPerfCounters(), 1, 1, 0, 0, 0, 0, &expected); |
| setExpectedCountersForStencilOps(getPerfCounters(), 0, 0, 0, 0, 0, &expected); |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); |
| GLFramebuffer framebuffer; |
| GLTexture texture; |
| GLRenderbuffer renderbuffer; |
| setupClearAndDrawForDepthStencilOpsTest(&program, &framebuffer, &texture, &renderbuffer, false); |
| |
| // Execute the scenario that this test is for: |
| |
| // Invalidate (storeOp = DONT_CARE; mContentDefined = false) |
| const GLenum discards[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT}; |
| glInvalidateFramebuffer(GL_FRAMEBUFFER, 2, discards); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Disable (shouldn't change result) |
| glDisable(GL_DEPTH_TEST); |
| glDisable(GL_STENCIL_TEST); |
| |
| // Draw (since disabled, shouldn't change result) |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Ensure that the render pass wasn't broken |
| EXPECT_EQ(expected.renderPasses, getPerfCounters().renderPasses); |
| |
| // Use swapBuffers and then check how many loads and stores were actually done |
| swapBuffers(); |
| compareDepthStencilOpCounters(getPerfCounters(), expected); |
| |
| // Start and end another render pass, to check that the load ops are as expected |
| setAndIncrementDepthStencilLoadCountersForOpsTest(getPerfCounters(), 0, 0, &expected); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| swapBuffers(); |
| compareDepthStencilLoadOpCounters(getPerfCounters(), expected); |
| } |
| |
| // Tests that alternative PUBG MOBILE case does not break render pass, and that counts are correct: |
| // |
| // - Scenario: disable, invalidate, draw |
| TEST_P(VulkanPerformanceCounterTest, DisableInvalidateDraw) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| angle::VulkanPerfCounters expected; |
| |
| // Expect rpCount+1, depth(Clears+1, Loads+0, LoadNones+0, Stores+0, StoreNones+0), |
| // stencil(Clears+0, Loads+0, LoadNones+0, Stores+0, StoreNones+0) |
| setExpectedCountersForDepthOps(getPerfCounters(), 1, 1, 0, 0, 0, 0, &expected); |
| setExpectedCountersForStencilOps(getPerfCounters(), 0, 0, 0, 0, 0, &expected); |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); |
| GLFramebuffer framebuffer; |
| GLTexture texture; |
| GLRenderbuffer renderbuffer; |
| setupClearAndDrawForDepthStencilOpsTest(&program, &framebuffer, &texture, &renderbuffer, false); |
| |
| // Execute the scenario that this test is for: |
| |
| // Disable (shouldn't change result) |
| glDisable(GL_DEPTH_TEST); |
| glDisable(GL_STENCIL_TEST); |
| |
| // Invalidate (storeOp = DONT_CARE; mContentDefined = false) |
| const GLenum discards[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT}; |
| glInvalidateFramebuffer(GL_FRAMEBUFFER, 2, discards); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Draw (since disabled, shouldn't change result) |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Ensure that the render pass wasn't broken |
| EXPECT_EQ(expected.renderPasses, getPerfCounters().renderPasses); |
| |
| // Use swapBuffers and then check how many loads and stores were actually done |
| swapBuffers(); |
| compareDepthStencilOpCounters(getPerfCounters(), expected); |
| |
| // Start and end another render pass, to check that the load ops are as expected |
| setAndIncrementDepthStencilLoadCountersForOpsTest(getPerfCounters(), 0, 0, &expected); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| swapBuffers(); |
| compareDepthStencilLoadOpCounters(getPerfCounters(), expected); |
| } |
| |
| // Tests that another case does not break render pass, and that counts are correct: |
| // |
| // - Scenario: disable, draw, invalidate, enable |
| TEST_P(VulkanPerformanceCounterTest, DisableDrawInvalidateEnable) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| angle::VulkanPerfCounters expected; |
| |
| // Expect rpCount+1, depth(Clears+1, Loads+0, LoadNones+0, Stores+0, StoreNones+0), |
| // stencil(Clears+0, Loads+0, LoadNones+0, Stores+0, StoreNones+0) |
| setExpectedCountersForDepthOps(getPerfCounters(), 1, 1, 0, 0, 0, 0, &expected); |
| setExpectedCountersForStencilOps(getPerfCounters(), 0, 0, 0, 0, 0, &expected); |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); |
| GLFramebuffer framebuffer; |
| GLTexture texture; |
| GLRenderbuffer renderbuffer; |
| setupClearAndDrawForDepthStencilOpsTest(&program, &framebuffer, &texture, &renderbuffer, false); |
| |
| // Execute the scenario that this test is for: |
| |
| // Note: setupClearAndDrawForDepthStencilOpsTest() did an enable and draw |
| |
| // Disable (since not invalidated, shouldn't change result) |
| glDisable(GL_DEPTH_TEST); |
| glDisable(GL_STENCIL_TEST); |
| |
| // Draw (since not invalidated, shouldn't change result) |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Invalidate (should result: in storeOp = DONT_CARE; mContentDefined = false) |
| const GLenum discards[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT}; |
| glInvalidateFramebuffer(GL_FRAMEBUFFER, 2, discards); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Enable (shouldn't change result) |
| glEnable(GL_DEPTH_TEST); |
| glEnable(GL_STENCIL_TEST); |
| // Note: The above enable calls will be ignored, since no drawing was done to force the enable |
| // dirty bit to be processed |
| |
| // Ensure that the render pass wasn't broken |
| EXPECT_EQ(expected.renderPasses, getPerfCounters().renderPasses); |
| |
| // Break the render pass by reading back a pixel. |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| |
| // Use swapBuffers and then check how many loads and stores were actually done |
| swapBuffers(); |
| compareDepthStencilOpCounters(getPerfCounters(), expected); |
| |
| // Start and end another render pass, to check that the load ops are as expected |
| setAndIncrementDepthStencilLoadCountersForOpsTest(getPerfCounters(), 0, 0, &expected); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| swapBuffers(); |
| compareDepthStencilLoadOpCounters(getPerfCounters(), expected); |
| } |
| |
| // Tests that common TRex case does not break render pass, and that counts are correct: |
| // |
| // - Scenario: invalidate |
| TEST_P(VulkanPerformanceCounterTest, DepthStencilInvalidate) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| angle::VulkanPerfCounters expected; |
| |
| // Expect rpCount+1, depth(Clears+1, Loads+0, LoadNones+0, Stores+0, StoreNones+0), |
| // stencil(Clears+0, Loads+0, LoadNones+0, Stores+0, StoreNones+0) |
| setExpectedCountersForDepthOps(getPerfCounters(), 1, 1, 0, 0, 0, 0, &expected); |
| setExpectedCountersForStencilOps(getPerfCounters(), 0, 0, 0, 0, 0, &expected); |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); |
| GLFramebuffer framebuffer; |
| GLTexture texture; |
| GLRenderbuffer renderbuffer; |
| setupClearAndDrawForDepthStencilOpsTest(&program, &framebuffer, &texture, &renderbuffer, false); |
| |
| // Execute the scenario that this test is for: |
| |
| // Invalidate (storeOp = DONT_CARE; mContentDefined = false) |
| const GLenum discards[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT}; |
| glInvalidateFramebuffer(GL_FRAMEBUFFER, 2, discards); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Ensure that the render pass wasn't broken |
| EXPECT_EQ(expected.renderPasses, getPerfCounters().renderPasses); |
| |
| // Use swapBuffers and then check how many loads and stores were actually done |
| swapBuffers(); |
| compareDepthStencilOpCounters(getPerfCounters(), expected); |
| |
| // Start and end another render pass, to check that the load ops are as expected |
| setAndIncrementDepthStencilLoadCountersForOpsTest(getPerfCounters(), 0, 0, &expected); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| swapBuffers(); |
| compareDepthStencilLoadOpCounters(getPerfCounters(), expected); |
| } |
| |
| // Similar to Invalidate, but uses glInvalidateSubFramebuffer such that the given area covers the |
| // whole framebuffer. |
| TEST_P(VulkanPerformanceCounterTest, DepthStencilInvalidateSub) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| angle::VulkanPerfCounters expected; |
| |
| // Expect rpCount+1, depth(Clears+1, Loads+0, LoadNones+0, Stores+0, StoreNones+0), |
| // stencil(Clears+0, Loads+0, LoadNones+0, Stores+0, StoreNones+0) |
| setExpectedCountersForDepthOps(getPerfCounters(), 1, 1, 0, 0, 0, 0, &expected); |
| setExpectedCountersForStencilOps(getPerfCounters(), 0, 0, 0, 0, 0, &expected); |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); |
| GLFramebuffer framebuffer; |
| GLTexture texture; |
| GLRenderbuffer renderbuffer; |
| setupClearAndDrawForDepthStencilOpsTest(&program, &framebuffer, &texture, &renderbuffer, false); |
| |
| // Execute the scenario that this test is for: |
| |
| // Invalidate (storeOp = DONT_CARE; mContentDefined = false) |
| const GLenum discards[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT}; |
| glInvalidateSubFramebuffer(GL_FRAMEBUFFER, 2, discards, -100, -100, kOpsTestSize + 200, |
| kOpsTestSize + 200); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Ensure that the render pass wasn't broken |
| EXPECT_EQ(expected.renderPasses, getPerfCounters().renderPasses); |
| |
| // Use swapBuffers and then check how many loads and stores were actually done |
| swapBuffers(); |
| compareDepthStencilOpCounters(getPerfCounters(), expected); |
| |
| // Start and end another render pass, to check that the load ops are as expected |
| setAndIncrementDepthStencilLoadCountersForOpsTest(getPerfCounters(), 0, 0, &expected); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| swapBuffers(); |
| compareDepthStencilLoadOpCounters(getPerfCounters(), expected); |
| } |
| |
| // Similar to InvalidateSub, but uses glInvalidateSubFramebuffer such that the given area does NOT |
| // covers the whole framebuffer. |
| TEST_P(VulkanPerformanceCounterTest, DepthStencilPartialInvalidateSub) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| angle::VulkanPerfCounters expected; |
| |
| // Expect rpCount+1, depth(Clears+1, Loads+0, LoadNones+0, Stores+1, StoreNones+0), |
| // stencil(Clears+1, Loads+0, LoadNones+0, Stores+1, StoreNones+0) |
| setExpectedCountersForDepthOps(getPerfCounters(), 1, 1, 0, 0, 1, 0, &expected); |
| setExpectedCountersForStencilOps(getPerfCounters(), 1, 0, 0, 1, 0, &expected); |
| |
| // Create the framebuffer and make sure depth/stencil have valid contents. |
| ANGLE_GL_PROGRAM(drawRed, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); |
| GLFramebuffer framebuffer; |
| GLTexture texture; |
| GLRenderbuffer renderbuffer; |
| setupClearAndDrawForDepthStencilOpsTest(&drawRed, &framebuffer, &texture, &renderbuffer, true); |
| |
| // Break the render pass so depth/stencil values are stored. |
| EXPECT_EQ(expected.renderPasses, getPerfCounters().renderPasses); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| compareDepthStencilOpCounters(getPerfCounters(), expected); |
| |
| // Start a new render pass that is scissored. Depth/stencil should be loaded. The draw call is |
| // followed by an invalidate, so store shouldn't happen. |
| |
| // Expect rpCount+1, depth(Clears+0, Loads+1, LoadNones+0, Stores+0, StoreNones+0), |
| // stencil(Clears+0, Loads+1, LoadNones+0, Stores+0, StoreNones+0) |
| setExpectedCountersForDepthOps(getPerfCounters(), 1, 0, 1, 0, 0, 0, &expected); |
| setExpectedCountersForStencilOps(getPerfCounters(), 0, 1, 0, 0, 0, &expected); |
| |
| glEnable(GL_SCISSOR_TEST); |
| glScissor(kOpsTestSize / 8, kOpsTestSize / 4, kOpsTestSize / 2, kOpsTestSize / 3); |
| |
| glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); |
| glStencilFunc(GL_ALWAYS, 0x55, 0xFF); |
| glDepthFunc(GL_ALWAYS); |
| |
| ANGLE_GL_PROGRAM(drawGreen, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green()); |
| drawQuad(drawGreen, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| |
| const GLenum discards[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT}; |
| glInvalidateSubFramebuffer(GL_FRAMEBUFFER, 2, discards, kOpsTestSize / 8, kOpsTestSize / 8, |
| 7 * kOpsTestSize / 8, 7 * kOpsTestSize / 8); |
| |
| // Break the render pass so depth/stencil values are discarded. |
| EXPECT_EQ(expected.renderPasses, getPerfCounters().renderPasses); |
| EXPECT_PIXEL_COLOR_EQ(kOpsTestSize / 2, kOpsTestSize / 2, GLColor::green); |
| compareDepthStencilOpCounters(getPerfCounters(), expected); |
| |
| // Start another render pass without scissor. Because parts of the framebuffer attachments were |
| // not invalidated, depth/stencil should be loaded. |
| |
| // Expect rpCount+1, depth(Clears+0, Loads+1, LoadNones+0, Stores+1, StoreNones+0), |
| // stencil(Clears+0, Loads+1, LoadNones+0, Stores+1, StoreNones+0) |
| setExpectedCountersForDepthOps(getPerfCounters(), 1, 0, 1, 0, 1, 0, &expected); |
| setExpectedCountersForStencilOps(getPerfCounters(), 0, 1, 0, 1, 0, &expected); |
| |
| glDisable(GL_SCISSOR_TEST); |
| |
| ANGLE_GL_PROGRAM(drawBlue, essl1_shaders::vs::Simple(), essl1_shaders::fs::Blue()); |
| drawQuad(drawBlue, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Verify results |
| EXPECT_EQ(expected.renderPasses, getPerfCounters().renderPasses); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue); |
| compareDepthStencilOpCounters(getPerfCounters(), expected); |
| } |
| |
| // Tests that another case does not break render pass, and that counts are correct: |
| // |
| // - Scenario: invalidate, draw |
| TEST_P(VulkanPerformanceCounterTest, DepthStencilInvalidateDraw) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| angle::VulkanPerfCounters expected; |
| |
| // Expect rpCount+1, depth(Clears+1, Loads+0, LoadNones+0, Stores+1, StoreNones+0), |
| // stencil(Clears+0, Loads+0, LoadNones+0, Stores+0, StoreNones+0) |
| setExpectedCountersForDepthOps(getPerfCounters(), 1, 1, 0, 0, 1, 0, &expected); |
| setExpectedCountersForStencilOps(getPerfCounters(), 0, 0, 0, 0, 0, &expected); |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); |
| GLFramebuffer framebuffer; |
| GLTexture texture; |
| GLRenderbuffer renderbuffer; |
| setupClearAndDrawForDepthStencilOpsTest(&program, &framebuffer, &texture, &renderbuffer, false); |
| |
| // Execute the scenario that this test is for: |
| |
| // Invalidate (should result: in storeOp = DONT_CARE; mContentDefined = false) |
| const GLenum discards[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT}; |
| glInvalidateFramebuffer(GL_FRAMEBUFFER, 2, discards); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Draw (since enabled, should result: in storeOp = STORE; mContentDefined = true) |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Ensure that the render pass wasn't broken |
| EXPECT_EQ(expected.renderPasses, getPerfCounters().renderPasses); |
| |
| // Use swapBuffers and then check how many loads and stores were actually done |
| swapBuffers(); |
| compareDepthStencilOpCounters(getPerfCounters(), expected); |
| |
| // Start and end another render pass, to check that the load ops are as expected |
| setAndIncrementDepthStencilLoadCountersForOpsTest(getPerfCounters(), 1, 0, &expected); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| swapBuffers(); |
| compareDepthStencilLoadOpCounters(getPerfCounters(), expected); |
| } |
| |
| // Tests that another case does not break render pass, and that counts are correct: |
| // |
| // - Scenario: invalidate, draw, disable |
| TEST_P(VulkanPerformanceCounterTest, DepthStencilInvalidateDrawDisable) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| // http://anglebug.com/6857 |
| ANGLE_SKIP_TEST_IF(IsLinux() && IsAMD() && IsVulkan()); |
| |
| angle::VulkanPerfCounters expected; |
| |
| // Expect rpCount+1, depth(Clears+1, Loads+0, LoadNones+0, Stores+1, StoreNones+0), |
| // stencil(Clears+0, Loads+0, LoadNones+0, Stores+0, StoreNones+0) |
| setExpectedCountersForDepthOps(getPerfCounters(), 1, 1, 0, 0, 1, 0, &expected); |
| setExpectedCountersForStencilOps(getPerfCounters(), 0, 0, 0, 0, 0, &expected); |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); |
| GLFramebuffer framebuffer; |
| GLTexture texture; |
| GLRenderbuffer renderbuffer; |
| setupClearAndDrawForDepthStencilOpsTest(&program, &framebuffer, &texture, &renderbuffer, false); |
| |
| // Execute the scenario that this test is for: |
| |
| // Invalidate (should result: in storeOp = DONT_CARE; mContentDefined = false) |
| const GLenum discards[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT}; |
| glInvalidateFramebuffer(GL_FRAMEBUFFER, 2, discards); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Draw (since enabled, should result: in storeOp = STORE; mContentDefined = true) |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Disable (shouldn't change result) |
| glDisable(GL_DEPTH_TEST); |
| glDisable(GL_STENCIL_TEST); |
| // Note: this draw is just so that the disable dirty bits will be processed |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Ensure that the render pass wasn't broken |
| EXPECT_EQ(expected.renderPasses, getPerfCounters().renderPasses); |
| |
| // Break the render pass and then check how many loads and stores were actually done |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| compareDepthStencilOpCounters(getPerfCounters(), expected); |
| |
| // Start and end another render pass, to check that the load ops are as expected |
| setAndIncrementDepthStencilLoadCountersForOpsTest(getPerfCounters(), 1, 1, &expected); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| compareDepthStencilLoadOpCounters(getPerfCounters(), expected); |
| } |
| |
| // Tests that another case does not break render pass, and that counts are correct: |
| // |
| // - Scenario: invalidate, disable, draw, enable |
| TEST_P(VulkanPerformanceCounterTest, DepthStencilInvalidateDisableDrawEnable) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| angle::VulkanPerfCounters expected; |
| |
| // Expect rpCount+1, depth(Clears+1, Loads+0, LoadNones+0, Stores+0, StoreNones+0), |
| // stencil(Clears+0, Loads+0, LoadNones+0, Stores+0, StoreNones+0) |
| setExpectedCountersForDepthOps(getPerfCounters(), 1, 1, 0, 0, 0, 0, &expected); |
| setExpectedCountersForStencilOps(getPerfCounters(), 0, 0, 0, 0, 0, &expected); |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); |
| GLFramebuffer framebuffer; |
| GLTexture texture; |
| GLRenderbuffer renderbuffer; |
| setupClearAndDrawForDepthStencilOpsTest(&program, &framebuffer, &texture, &renderbuffer, false); |
| |
| // Execute the scenario that this test is for: |
| |
| // Invalidate (should result: in storeOp = DONT_CARE; mContentDefined = false) |
| const GLenum discards[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT}; |
| glInvalidateFramebuffer(GL_FRAMEBUFFER, 2, discards); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Disable (shouldn't change result) |
| glDisable(GL_DEPTH_TEST); |
| glDisable(GL_STENCIL_TEST); |
| |
| // Draw (since disabled, shouldn't change result) |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Enable (shouldn't change result) |
| glEnable(GL_DEPTH_TEST); |
| glEnable(GL_STENCIL_TEST); |
| // Note: The above enable calls will be ignored, since no drawing was done to force the enable |
| // dirty bit to be processed |
| |
| // Ensure that the render pass wasn't broken |
| EXPECT_EQ(expected.renderPasses, getPerfCounters().renderPasses); |
| |
| // Use swapBuffers and then check how many loads and stores were actually done |
| swapBuffers(); |
| compareDepthStencilOpCounters(getPerfCounters(), expected); |
| |
| // Start and end another render pass, to check that the load ops are as expected |
| setAndIncrementDepthStencilLoadCountersForOpsTest(getPerfCounters(), 0, 0, &expected); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| swapBuffers(); |
| compareDepthStencilLoadOpCounters(getPerfCounters(), expected); |
| } |
| |
| // Tests that another case does not break render pass, and that counts are correct: |
| // |
| // - Scenario: invalidate, disable, draw, enable, draw |
| TEST_P(VulkanPerformanceCounterTest, DepthStencilInvalidateDisableDrawEnableDraw) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| angle::VulkanPerfCounters expected; |
| |
| // Expect rpCount+1, depth(Clears+1, Loads+0, LoadNones+0, Stores+1, StoreNones+0), |
| // stencil(Clears+0, Loads+0, LoadNones+0, Stores+1, StoreNones+0) |
| setExpectedCountersForDepthOps(getPerfCounters(), 1, 1, 0, 0, 1, 0, &expected); |
| setExpectedCountersForStencilOps(getPerfCounters(), 0, 0, 0, 1, 0, &expected); |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); |
| GLFramebuffer framebuffer; |
| GLTexture texture; |
| GLRenderbuffer renderbuffer; |
| setupClearAndDrawForDepthStencilOpsTest(&program, &framebuffer, &texture, &renderbuffer, false); |
| |
| // Execute the scenario that this test is for: |
| |
| // Invalidate (should result: in storeOp = DONT_CARE; mContentDefined = false) |
| const GLenum discards[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT}; |
| glInvalidateFramebuffer(GL_FRAMEBUFFER, 2, discards); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Disable (shouldn't change result) |
| glDisable(GL_DEPTH_TEST); |
| glDisable(GL_STENCIL_TEST); |
| |
| // Draw (since disabled, shouldn't change result) |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Enable (shouldn't change result) |
| glEnable(GL_DEPTH_TEST); |
| glEnable(GL_STENCIL_TEST); |
| glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); |
| |
| // Draw (since enabled, should result: in storeOp = STORE; mContentDefined = true) |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Ensure that the render pass wasn't broken |
| EXPECT_EQ(expected.renderPasses, getPerfCounters().renderPasses); |
| |
| // Break the render pass and then check how many loads and stores were actually done |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| compareDepthStencilOpCounters(getPerfCounters(), expected); |
| |
| // Start and end another render pass, to check that the load ops are as expected |
| setAndIncrementDepthStencilLoadCountersForOpsTest(getPerfCounters(), 1, 1, &expected); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| compareDepthStencilLoadOpCounters(getPerfCounters(), expected); |
| } |
| |
| // Tests that another case does not break render pass, and that counts are correct: |
| // |
| // - Scenario: invalidate, draw, disable, enable |
| TEST_P(VulkanPerformanceCounterTest, DepthStencilInvalidateDrawDisableEnable) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| angle::VulkanPerfCounters expected; |
| |
| // Expect rpCount+1, depth(Clears+1, Loads+0, LoadNones+0, Stores+1, StoreNones+0), |
| // stencil(Clears+0, Loads+0, LoadNones+0, Stores+0, StoreNones+0) |
| setExpectedCountersForDepthOps(getPerfCounters(), 1, 1, 0, 0, 1, 0, &expected); |
| setExpectedCountersForStencilOps(getPerfCounters(), 0, 0, 0, 0, 0, &expected); |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); |
| GLFramebuffer framebuffer; |
| GLTexture texture; |
| GLRenderbuffer renderbuffer; |
| setupClearAndDrawForDepthStencilOpsTest(&program, &framebuffer, &texture, &renderbuffer, false); |
| |
| // Execute the scenario that this test is for: |
| |
| // Invalidate (should result: in storeOp = DONT_CARE; mContentDefined = false) |
| const GLenum discards[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT}; |
| glInvalidateFramebuffer(GL_FRAMEBUFFER, 2, discards); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Draw (since enabled, should result: in storeOp = STORE; mContentDefined = true) |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Disable (shouldn't change result) |
| glDisable(GL_DEPTH_TEST); |
| glDisable(GL_STENCIL_TEST); |
| // Note: this draw is just so that the disable dirty bits will be processed |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Enable (shouldn't change result) |
| glEnable(GL_DEPTH_TEST); |
| glEnable(GL_STENCIL_TEST); |
| // Note: The above enable calls will be ignored, since no drawing was done to force the enable |
| // dirty bit to be processed |
| |
| // Ensure that the render pass wasn't broken |
| EXPECT_EQ(expected.renderPasses, getPerfCounters().renderPasses); |
| |
| // Break the render pass and then check how many loads and stores were actually done |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| compareDepthStencilOpCounters(getPerfCounters(), expected); |
| |
| // Start and end another render pass, to check that the load ops are as expected |
| setAndIncrementDepthStencilLoadCountersForOpsTest(getPerfCounters(), 1, 0, &expected); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| compareDepthStencilLoadOpCounters(getPerfCounters(), expected); |
| } |
| |
| // Tests that another case does not break render pass, and that counts are correct: |
| // |
| // - Scenario: invalidate, draw, disable, enable, invalidate |
| TEST_P(VulkanPerformanceCounterTest, DepthStencilInvalidateDrawDisableEnableInvalidate) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| angle::VulkanPerfCounters expected; |
| |
| // Expect rpCount+1, depth(Clears+1, Loads+0, LoadNones+0, Stores+0, StoreNones+0), |
| // stencil(Clears+0, Loads+0, LoadNones+0, Stores+0, StoreNones+0) |
| setExpectedCountersForDepthOps(getPerfCounters(), 1, 1, 0, 0, 0, 0, &expected); |
| setExpectedCountersForStencilOps(getPerfCounters(), 0, 0, 0, 0, 0, &expected); |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); |
| GLFramebuffer framebuffer; |
| GLTexture texture; |
| GLRenderbuffer renderbuffer; |
| setupClearAndDrawForDepthStencilOpsTest(&program, &framebuffer, &texture, &renderbuffer, false); |
| |
| // Execute the scenario that this test is for: |
| |
| // Invalidate (should result: in storeOp = DONT_CARE; mContentDefined = false) |
| const GLenum discards[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT}; |
| glInvalidateFramebuffer(GL_FRAMEBUFFER, 2, discards); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Draw (since enabled, should result: in storeOp = STORE; mContentDefined = true) |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Disable (shouldn't change result) |
| glDisable(GL_DEPTH_TEST); |
| glDisable(GL_STENCIL_TEST); |
| // Note: this draw is just so that the disable dirty bits will be processed |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Enable (shouldn't change result) |
| glEnable(GL_DEPTH_TEST); |
| glEnable(GL_STENCIL_TEST); |
| |
| // Invalidate (should result: in storeOp = DONT_CARE; mContentDefined = false) |
| glInvalidateFramebuffer(GL_FRAMEBUFFER, 2, discards); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Ensure that the render pass wasn't broken |
| EXPECT_EQ(expected.renderPasses, getPerfCounters().renderPasses); |
| |
| // Use swapBuffers and then check how many loads and stores were actually done |
| swapBuffers(); |
| compareDepthStencilOpCounters(getPerfCounters(), expected); |
| |
| // Start and end another render pass, to check that the load ops are as expected |
| setAndIncrementDepthStencilLoadCountersForOpsTest(getPerfCounters(), 0, 0, &expected); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| swapBuffers(); |
| compareDepthStencilLoadOpCounters(getPerfCounters(), expected); |
| } |
| |
| // Tests that another case does not break render pass, and that counts are correct: |
| // |
| // - Scenario: invalidate, draw, disable, enable, invalidate, draw |
| TEST_P(VulkanPerformanceCounterTest, DepthStencilInvalidateDrawDisableEnableInvalidateDraw) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| angle::VulkanPerfCounters expected; |
| |
| // Expect rpCount+1, depth(Clears+1, Loads+0, LoadNones+0, Stores+1, StoreNones+0), |
| // stencil(Clears+0, Loads+0, LoadNones+0, Stores+0, StoreNones+0) |
| setExpectedCountersForDepthOps(getPerfCounters(), 1, 1, 0, 0, 1, 0, &expected); |
| setExpectedCountersForStencilOps(getPerfCounters(), 0, 0, 0, 0, 0, &expected); |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); |
| GLFramebuffer framebuffer; |
| GLTexture texture; |
| GLRenderbuffer renderbuffer; |
| setupClearAndDrawForDepthStencilOpsTest(&program, &framebuffer, &texture, &renderbuffer, false); |
| |
| // Execute the scenario that this test is for: |
| |
| // Invalidate (should result: in storeOp = DONT_CARE; mContentDefined = false) |
| const GLenum discards[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT}; |
| glInvalidateFramebuffer(GL_FRAMEBUFFER, 2, discards); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Draw (since enabled, should result: in storeOp = STORE; mContentDefined = true) |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Disable (shouldn't change result) |
| glDisable(GL_DEPTH_TEST); |
| glDisable(GL_STENCIL_TEST); |
| // Note: this draw is just so that the disable dirty bits will be processed |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Enable (shouldn't change result) |
| glEnable(GL_DEPTH_TEST); |
| glEnable(GL_STENCIL_TEST); |
| |
| // Invalidate (should result: in storeOp = DONT_CARE; mContentDefined = false) |
| glInvalidateFramebuffer(GL_FRAMEBUFFER, 2, discards); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Draw (since enabled, should result: in storeOp = STORE; mContentDefined = true) |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Ensure that the render pass wasn't broken |
| EXPECT_EQ(expected.renderPasses, getPerfCounters().renderPasses); |
| |
| // Use swapBuffers and then check how many loads and stores were actually done |
| swapBuffers(); |
| compareDepthStencilOpCounters(getPerfCounters(), expected); |
| |
| // Start and end another render pass, to check that the load ops are as expected |
| setAndIncrementDepthStencilLoadCountersForOpsTest(getPerfCounters(), 1, 0, &expected); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| swapBuffers(); |
| compareDepthStencilLoadOpCounters(getPerfCounters(), expected); |
| } |
| |
| // Tests that another common (dEQP) case does not break render pass, and that counts are correct: |
| // |
| // - Scenario: invalidate, disable, enable, draw |
| TEST_P(VulkanPerformanceCounterTest, DepthStencilInvalidateDisableEnableDraw) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| angle::VulkanPerfCounters expected; |
| |
| // Expect rpCount+1, depth(Clears+1, Loads+0, LoadNones+0, Stores+1, StoreNones+0), |
| // stencil(Clears+0, Loads+0, LoadNones+0, Stores+0, StoreNones+0) |
| setExpectedCountersForDepthOps(getPerfCounters(), 1, 1, 0, 0, 1, 0, &expected); |
| setExpectedCountersForStencilOps(getPerfCounters(), 0, 0, 0, 0, 0, &expected); |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); |
| GLFramebuffer framebuffer; |
| GLTexture texture; |
| GLRenderbuffer renderbuffer; |
| setupClearAndDrawForDepthStencilOpsTest(&program, &framebuffer, &texture, &renderbuffer, false); |
| |
| // Execute the scenario that this test is for: |
| |
| // Invalidate (should result: in storeOp = DONT_CARE; mContentDefined = false) |
| const GLenum discards[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT}; |
| glInvalidateFramebuffer(GL_FRAMEBUFFER, 2, discards); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Disable (shouldn't change result) |
| glDisable(GL_DEPTH_TEST); |
| glDisable(GL_STENCIL_TEST); |
| // Note: this draw is just so that the disable dirty bits will be processed |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Enable (shouldn't change result) |
| glEnable(GL_DEPTH_TEST); |
| glEnable(GL_STENCIL_TEST); |
| |
| // Draw (since enabled, should result: in storeOp = STORE; mContentDefined = true) |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Ensure that the render pass wasn't broken |
| EXPECT_EQ(expected.renderPasses, getPerfCounters().renderPasses); |
| |
| // Use swapBuffers and then check how many loads and stores were actually done |
| swapBuffers(); |
| compareDepthStencilOpCounters(getPerfCounters(), expected); |
| |
| // Start and end another render pass, to check that the load ops are as expected |
| setAndIncrementDepthStencilLoadCountersForOpsTest(getPerfCounters(), 1, 0, &expected); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| swapBuffers(); |
| compareDepthStencilLoadOpCounters(getPerfCounters(), expected); |
| } |
| |
| // Tests that an in renderpass clear after invalidate keeps content stored. |
| TEST_P(VulkanPerformanceCounterTest, DepthStencilInvalidateAndClear) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| angle::VulkanPerfCounters expected; |
| |
| // Expect rpCount+1, depth(Clears+1, Loads+0, LoadNones+0, Stores+1, StoreNones+0), |
| // stencil(Clears+0, Loads+0, LoadNones+0, Stores+0, StoreNones+0) |
| setExpectedCountersForDepthOps(getPerfCounters(), 1, 1, 0, 0, 1, 0, &expected); |
| setExpectedCountersForStencilOps(getPerfCounters(), 0, 0, 0, 0, 0, &expected); |
| |
| // Clear should vkCmdClearAttachments |
| expected.depthClearAttachments = getPerfCounters().depthClearAttachments + 1; |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); |
| GLFramebuffer framebuffer; |
| GLTexture texture; |
| GLRenderbuffer renderbuffer; |
| setupClearAndDrawForDepthStencilOpsTest(&program, &framebuffer, &texture, &renderbuffer, false); |
| |
| // Disable depth test but with depth mask enabled so that clear should still work. |
| glDisable(GL_DEPTH_TEST); |
| glDepthMask(GL_TRUE); |
| |
| // Invalidate (should result: in storeOp = DONT_CARE; mContentDefined = false) |
| const GLenum discards[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT}; |
| glInvalidateFramebuffer(GL_FRAMEBUFFER, 2, discards); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Do in-renderpass clear. This should result in StoreOp=STORE; mContentDefined = true. |
| glClearDepthf(1.0f); |
| glClear(GL_DEPTH_BUFFER_BIT); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Use swapBuffers and then check how many loads and stores were actually done |
| swapBuffers(); |
| compareDepthStencilOpCounters(getPerfCounters(), expected); |
| compareClearAttachmentsCounter(expected.depthClearAttachments, |
| getPerfCounters().depthClearAttachments); |
| |
| // Expect rpCount+1, depth(Clears+0, Loads+1, LoadNones+0, Stores+1, StoreNones+0), |
| // stencil(Clears+0, Loads+0, LoadNones+0, Stores+0, StoreNones+0) |
| setExpectedCountersForDepthOps(getPerfCounters(), 1, 0, 1, 0, 1, 0, &expected); |
| setExpectedCountersForStencilOps(getPerfCounters(), 0, 0, 0, 0, 0, &expected); |
| |
| // Bind FBO again and try to use the depth buffer without clear. This should result in |
| // loadOp=LOAD and StoreOP=STORE |
| glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); |
| glEnable(GL_DEPTH_TEST); |
| glDepthFunc(GL_LESS); |
| glDisable(GL_STENCIL_TEST); |
| ANGLE_GL_PROGRAM(blueProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Blue()); |
| // Should pass depth test: (0.5+1.0)/2.0=0.75 < 1.0 |
| drawQuad(blueProgram, essl1_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_COLOR_EQ(kOpsTestSize / 2, kOpsTestSize / 2, GLColor::blue); |
| compareDepthStencilOpCounters(getPerfCounters(), expected); |
| } |
| |
| // Tests that the draw path for clear after invalidate and disabling depth/stencil test keeps |
| // content stored. |
| TEST_P(VulkanPerformanceCounterTest, DepthStencilInvalidateAndMaskedClear) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| angle::VulkanPerfCounters expected; |
| |
| // Expect rpCount+1, depth(Clears+1, Loads+0, LoadNones+0, Stores+1, StoreNones+0), |
| // stencil(Clears+1, Loads+0, LoadNones+0, Stores+1, StoreNones+0) |
| setExpectedCountersForDepthOps(getPerfCounters(), 1, 1, 0, 0, 1, 0, &expected); |
| setExpectedCountersForStencilOps(getPerfCounters(), 1, 0, 0, 1, 0, &expected); |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); |
| GLFramebuffer framebuffer; |
| GLTexture texture; |
| GLRenderbuffer renderbuffer; |
| setupClearAndDrawForDepthStencilOpsTest(&program, &framebuffer, &texture, &renderbuffer, true); |
| |
| // Invalidate (should result: in storeOp = DONT_CARE; mContentDefined = false) |
| const GLenum discards[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT}; |
| glInvalidateFramebuffer(GL_FRAMEBUFFER, 2, discards); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Disable depth/stencil test but make stencil masked |
| glDisable(GL_DEPTH_TEST); |
| glDisable(GL_STENCIL_TEST); |
| glDepthMask(GL_TRUE); |
| glStencilMask(0xF0); |
| |
| // Enable scissor for the draw path to be taken. |
| glEnable(GL_SCISSOR_TEST); |
| glScissor(kOpsTestSize / 4, kOpsTestSize / 4, kOpsTestSize / 2, kOpsTestSize / 2); |
| |
| // Do in-renderpass clear. This should result in StoreOp=STORE |
| glClearDepthf(1.0f); |
| glClearStencil(0x55); |
| glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Use swapBuffers and then check how many loads and stores were actually done |
| swapBuffers(); |
| compareDepthStencilOpCounters(getPerfCounters(), expected); |
| |
| // Expect rpCount+1, depth(Clears+0, Loads+1, LoadNones+0, Stores+1, StoreNones+0), |
| // stencil(Clears+0, Loads+1, LoadNones+0, Stores+0, StoreNones+1) |
| // Note that depth write is enabled, while stencil is disabled. |
| setExpectedCountersForDepthOps(getPerfCounters(), 1, 0, 1, 0, 1, 0, &expected); |
| setExpectedCountersForStencilOps(getPerfCounters(), 0, 1, 0, 0, 1, &expected); |
| |
| // Bind FBO again and try to use the depth buffer without clear. This should result in |
| // loadOp=LOAD and StoreOP=STORE |
| glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); |
| glEnable(GL_DEPTH_TEST); |
| glDepthFunc(GL_LESS); |
| glEnable(GL_STENCIL_TEST); |
| glStencilFunc(GL_EQUAL, 0x50, 0xF0); |
| glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); |
| glStencilMask(0xFF); |
| ANGLE_GL_PROGRAM(blueProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Blue()); |
| drawQuad(blueProgram, essl1_shaders::PositionAttrib(), 0.95f); |
| EXPECT_PIXEL_COLOR_EQ(kOpsTestSize / 2, kOpsTestSize / 2, GLColor::blue); |
| compareDepthStencilOpCounters(getPerfCounters(), expected); |
| } |
| |
| // Tests whether depth-stencil ContentDefined will be correct when: |
| // |
| // - Scenario: invalidate, detach D/S texture and modify it, attach D/S texture, draw with blend |
| TEST_P(VulkanPerformanceCounterTest, DepthStencilInvalidateDetachModifyTexAttachDrawWithBlend) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| angle::VulkanPerfCounters expected; |
| |
| // Expect rpCount+1, depth(Clears+1, Loads+0, LoadNones+0, Stores+0, StoreNones+0), |
| // stencil(Clears+0, Loads+0, LoadNones+0, Stores+0, StoreNones+0) |
| setExpectedCountersForDepthOps(getPerfCounters(), 1, 1, 0, 0, 0, 0, &expected); |
| setExpectedCountersForStencilOps(getPerfCounters(), 0, 0, 0, 0, 0, &expected); |
| |
| ANGLE_GL_PROGRAM(redProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); |
| ANGLE_GL_PROGRAM(greenProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green()); |
| GLFramebuffer framebuffer; |
| glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); |
| |
| GLTexture colorTexture; |
| glBindTexture(GL_TEXTURE_2D, colorTexture); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture, 0); |
| |
| GLTexture depthStencilTexture; |
| glBindTexture(GL_TEXTURE_2D, depthStencilTexture); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, 2, 2, 0, GL_DEPTH_STENCIL, |
| GL_UNSIGNED_INT_24_8, nullptr); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, |
| depthStencilTexture, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| // Clear and draw with depth-stencil enabled |
| glEnable(GL_DEPTH_TEST); |
| glDepthMask(GL_TRUE); |
| glDepthFunc(GL_LEQUAL); |
| glClearDepthf(0.99f); |
| glEnable(GL_STENCIL_TEST); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
| drawQuad(redProgram, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Invalidate depth & stencil (should result: in storeOp = DONT_CARE; mContentDefined = false) |
| const GLenum discards[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT}; |
| glInvalidateFramebuffer(GL_FRAMEBUFFER, 2, discards); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Check for the expected number of render passes, expected color, and other expected counters |
| EXPECT_EQ(expected.renderPasses, getPerfCounters().renderPasses); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| compareDepthStencilOpCounters(getPerfCounters(), expected); |
| |
| // Detach depth-stencil attachment |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| // Modify depth-stencil |
| constexpr uint32_t kDepthStencilInitialValue = 0xafffff00; |
| uint32_t depthStencilData[4] = {kDepthStencilInitialValue, kDepthStencilInitialValue, |
| kDepthStencilInitialValue, kDepthStencilInitialValue}; |
| glBindTexture(GL_TEXTURE_2D, depthStencilTexture); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, 2, 2, 0, GL_DEPTH_STENCIL, |
| GL_UNSIGNED_INT_24_8, depthStencilData); |
| |
| // Re-attach depth-stencil |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, |
| depthStencilTexture, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| // Draw again, showing that the modified depth-stencil value prevents a new color value |
| // |
| // Expect rpCount+1, depth(Clears+0, Loads+1, LoadNones+0, Stores+1, StoreNones+0), |
| // stencil(Clears+0, Loads+1, LoadNones+0, Stores+0, StoreNones+1) |
| // Note that depth write is enabled, while stencil is disabled. |
| setExpectedCountersForDepthOps(getPerfCounters(), 1, 0, 1, 0, 1, 0, &expected); |
| setExpectedCountersForStencilOps(getPerfCounters(), 0, 1, 0, 0, 1, &expected); |
| drawQuad(greenProgram, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| // Check for the expected number of render passes, expected color, and other expected counters |
| EXPECT_EQ(expected.renderPasses, getPerfCounters().renderPasses); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| compareDepthStencilOpCounters(getPerfCounters(), expected); |
| |
| // Draw again, using a different depth value, so that the drawing takes place |
| // |
| // Expect rpCount+1, depth(Clears+0, Loads+1, LoadNones+0, Stores+1, StoreNones+0), |
| // stencil(Clears+0, Loads+1, LoadNones+0, Stores+0, StoreNones+1) |
| setExpectedCountersForDepthOps(getPerfCounters(), 1, 0, 1, 0, 1, 0, &expected); |
| setExpectedCountersForStencilOps(getPerfCounters(), 0, 1, 0, 0, 1, &expected); |
| drawQuad(greenProgram, essl1_shaders::PositionAttrib(), 0.2f); |
| ASSERT_GL_NO_ERROR(); |
| // Check for the expected number of render passes, expected color, and other expected counters |
| EXPECT_EQ(expected.renderPasses, getPerfCounters().renderPasses); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| compareDepthStencilOpCounters(getPerfCounters(), expected); |
| } |
| |
| // Tests that a GLRenderbuffer can be deleted before the render pass ends, and that everything |
| // still works. |
| // |
| // - Scenario: invalidate |
| TEST_P(VulkanPerformanceCounterTest, DepthStencilInvalidateDrawAndDeleteRenderbuffer) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| angle::VulkanPerfCounters expected; |
| |
| // Expect rpCount+1, depth(Clears+1, Loads+0, LoadNones+0, Stores+1, StoreNones+0), |
| // stencil(Clears+0, Loads+0, LoadNones+0, Stores+0, StoreNones+0) |
| setExpectedCountersForDepthOps(getPerfCounters(), 1, 1, 0, 0, 1, 0, &expected); |
| setExpectedCountersForStencilOps(getPerfCounters(), 0, 0, 0, 0, 0, &expected); |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); |
| GLFramebuffer framebuffer; |
| GLTexture texture; |
| { |
| // Declare the RAII-based GLRenderbuffer object within this set of curly braces, so that it |
| // will be deleted early (at the close-curly-brace) |
| GLRenderbuffer renderbuffer; |
| setupClearAndDrawForDepthStencilOpsTest(&program, &framebuffer, &texture, &renderbuffer, |
| false); |
| |
| // Invalidate (storeOp = DONT_CARE; mContentDefined = false) |
| const GLenum discards[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT}; |
| glInvalidateFramebuffer(GL_FRAMEBUFFER, 2, discards); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Draw (since enabled, should result: in storeOp = STORE; mContentDefined = true) |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Ensure that the render pass wasn't broken |
| EXPECT_EQ(expected.renderPasses, getPerfCounters().renderPasses); |
| } |
| |
| // The renderbuffer should now be deleted. |
| |
| // Use swapBuffers and then check how many loads and stores were actually done |
| swapBuffers(); |
| compareDepthStencilOpCounters(getPerfCounters(), expected); |
| |
| // Start and end another render pass, to check that the load ops are as expected |
| setAndIncrementDepthStencilLoadCountersForOpsTest(getPerfCounters(), 0, 0, &expected); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| swapBuffers(); |
| compareDepthStencilLoadOpCounters(getPerfCounters(), expected); |
| } |
| |
| // Test that disabling color buffer after clear continues to use loadOp for it. |
| // |
| // - Scenario: clear color and depth, disable color, draw, enable color, draw |
| TEST_P(VulkanPerformanceCounterTest_ES31, ColorDisableThenDrawThenEnableThenDraw) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| angle::VulkanPerfCounters expected; |
| |
| GLFramebuffer framebuffer; |
| GLTexture texture; |
| GLRenderbuffer renderbuffer; |
| setupForColorDepthOpsTest(&framebuffer, &texture, &renderbuffer); |
| |
| // Expected: |
| // rpCount+1, |
| // depth(Clears+1, Loads+0, LoadNones+0, Stores+1, StoreNones+0) |
| // color(Clears+1, Loads+0, LoadNones+0, Stores+1, StoreNones+0) |
| setExpectedCountersForDepthOps(getPerfCounters(), 0, 1, 0, 0, 1, 0, &expected); |
| setExpectedCountersForColorOps(getPerfCounters(), 1, 1, 0, 0, 1, 0, &expected); |
| |
| // Clear color and depth first |
| glClearColor(1, 0, 0, 1); |
| glClearDepthf(0.123); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
| |
| // Disable color output |
| GLenum drawBuffers[] = {GL_NONE}; |
| glDrawBuffers(1, drawBuffers); |
| |
| // Issue a draw call, only affecting depth |
| glDepthFunc(GL_ALWAYS); |
| ANGLE_GL_PROGRAM(drawGreen, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green()); |
| drawQuad(drawGreen, essl1_shaders::PositionAttrib(), 0.75f); |
| |
| // Enable color output |
| drawBuffers[0] = GL_COLOR_ATTACHMENT0; |
| glDrawBuffers(1, drawBuffers); |
| |
| // Issue another draw call, verifying depth simultaneously |
| glDepthFunc(GL_LESS); |
| ANGLE_GL_PROGRAM(drawBlue, essl1_shaders::vs::Simple(), essl1_shaders::fs::Blue()); |
| drawQuad(drawBlue, essl1_shaders::PositionAttrib(), 0.74f); |
| |
| EXPECT_EQ(expected.renderPasses, getPerfCounters().renderPasses); |
| |
| // Verify results and check how many loads and stores were actually done. |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue); |
| compareColorOpCounters(getPerfCounters(), expected); |
| compareDepthOpCounters(getPerfCounters(), expected); |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| // Tests that even if the app clears depth, it should be invalidated if there is no read. |
| TEST_P(VulkanPerformanceCounterTest, SwapShouldInvalidateDepthAfterClear) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| ANGLE_GL_PROGRAM(redProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); |
| |
| // Clear depth. |
| glClear(GL_DEPTH_BUFFER_BIT); |
| |
| // Ensure we never read from depth. |
| glDisable(GL_DEPTH_TEST); |
| |
| // Do one draw, then swap. |
| drawQuad(redProgram, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| |
| uint32_t expectedDepthClears = getPerfCounters().depthLoadOpClears; |
| |
| swapBuffers(); |
| |
| uint32_t actualDepthClears = getPerfCounters().depthLoadOpClears; |
| EXPECT_EQ(expectedDepthClears, actualDepthClears); |
| } |
| |
| // Tests that masked color clears don't break the RP. |
| TEST_P(VulkanPerformanceCounterTest, MaskedColorClearDoesNotBreakRenderPass) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| GLTexture texture; |
| glBindTexture(GL_TEXTURE_2D, texture); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| |
| GLFramebuffer framebuffer; |
| glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| ASSERT_GL_NO_ERROR(); |
| |
| uint32_t expectedRenderPassCount = getPerfCounters().renderPasses + 1; |
| |
| // Mask color channels and clear the framebuffer multiple times. |
| glClearColor(0.25f, 0.25f, 0.25f, 0.25f); |
| glColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_FALSE); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| glClearColor(0.5f, 0.5f, 0.5f, 0.5f); |
| glColorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_FALSE); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| glClearColor(1.0f, 1.0f, 1.0f, 1.0f); |
| glColorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_FALSE); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| glClearColor(0.75f, 0.75f, 0.75f, 0.75f); |
| glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| uint32_t actualRenderPassCount = getPerfCounters().renderPasses; |
| EXPECT_EQ(expectedRenderPassCount, actualRenderPassCount); |
| |
| EXPECT_PIXEL_NEAR(0, 0, 63, 127, 255, 191, 1); |
| } |
| |
| // Tests that masked color/depth/stencil clears don't break the RP. |
| TEST_P(VulkanPerformanceCounterTest, MaskedClearDoesNotBreakRenderPass) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| constexpr GLsizei kSize = 64; |
| |
| GLTexture texture; |
| glBindTexture(GL_TEXTURE_2D, texture); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| |
| GLRenderbuffer renderbuffer; |
| glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, kSize, kSize); |
| |
| GLFramebuffer framebuffer; |
| glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, |
| renderbuffer); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| ASSERT_GL_NO_ERROR(); |
| |
| uint32_t expectedRenderPassCount = getPerfCounters().renderPasses + 1; |
| |
| glEnable(GL_DEPTH_TEST); |
| glEnable(GL_STENCIL_TEST); |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Passthrough(), essl1_shaders::fs::UniformColor()); |
| glUseProgram(program); |
| GLint colorUniformLocation = |
| glGetUniformLocation(program, angle::essl1_shaders::ColorUniform()); |
| ASSERT_NE(-1, colorUniformLocation); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Clear the framebuffer with a draw call to start a render pass. |
| glViewport(0, 0, kSize, kSize); |
| glDepthFunc(GL_ALWAYS); |
| glStencilFunc(GL_ALWAYS, 0x55, 0xFF); |
| glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); |
| glUniform4f(colorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 1.0f); |
| |
| // Issue a masked clear. |
| glClearColor(0.25f, 1.0f, 0.25f, 1.25f); |
| glClearDepthf(0.0f); |
| glClearStencil(0x3F); |
| glColorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_FALSE); |
| glStencilMask(0xF0); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| // Make sure the render pass wasn't broken. |
| EXPECT_EQ(expectedRenderPassCount, getPerfCounters().renderPasses); |
| |
| // Verify that clear was done correctly. |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, GLColor::yellow); |
| EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, GLColor::yellow); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, GLColor::yellow); |
| EXPECT_PIXEL_COLOR_EQ(kSize / 2, kSize / 2, GLColor::yellow); |
| |
| glDisable(GL_SCISSOR_TEST); |
| glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); |
| glStencilMask(0xFF); |
| |
| // Make sure depth = 0.0f, stencil = 0x35 |
| glDepthFunc(GL_GREATER); |
| glStencilFunc(GL_EQUAL, 0x35, 0xFF); |
| glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); |
| |
| glUniform4f(colorUniformLocation, 0.0f, 0.0f, 1.0f, 1.0f); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.05f); |
| ASSERT_GL_NO_ERROR(); |
| |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(kSize / 2, kSize / 2, GLColor::blue); |
| } |
| |
| // Tests that clear followed by scissored draw uses loadOp to clear. |
| TEST_P(VulkanPerformanceCounterTest, ClearThenScissoredDraw) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| uint32_t expectedRenderPassCount = getPerfCounters().renderPasses + 1; |
| uint32_t expectedDepthClears = getPerfCounters().depthLoadOpClears + 1; |
| uint32_t expectedStencilClears = getPerfCounters().stencilLoadOpClears + 1; |
| |
| constexpr GLsizei kSize = 64; |
| |
| GLTexture texture; |
| glBindTexture(GL_TEXTURE_2D, texture); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| |
| GLRenderbuffer renderbuffer; |
| glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, kSize, kSize); |
| |
| GLFramebuffer framebuffer; |
| glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, |
| renderbuffer); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Clear depth/stencil |
| glClearColor(1.0f, 0.0f, 0.0f, 1.0f); |
| glClearDepthf(1.0f); |
| glClearStencil(0x55); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| // Issue a scissored draw call, expecting depth/stencil to be 1.0 and 0x55. |
| glViewport(0, 0, kSize, kSize); |
| glScissor(0, 0, kSize / 2, kSize); |
| glEnable(GL_SCISSOR_TEST); |
| |
| glEnable(GL_DEPTH_TEST); |
| glDepthFunc(GL_LESS); |
| |
| glEnable(GL_STENCIL_TEST); |
| glStencilFunc(GL_EQUAL, 0x55, 0xFF); |
| glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); |
| glStencilMask(0xFF); |
| |
| ANGLE_GL_PROGRAM(drawGreen, essl1_shaders::vs::Passthrough(), essl1_shaders::fs::Green()); |
| drawQuad(drawGreen, essl1_shaders::PositionAttrib(), 0.95f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Break the render pass. |
| GLTexture copyTex; |
| glBindTexture(GL_TEXTURE_2D, copyTex); |
| glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0, kSize, kSize, 0); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Make sure a single render pass was used and depth/stencil clear used loadOp=CLEAR. |
| EXPECT_EQ(expectedRenderPassCount, getPerfCounters().renderPasses); |
| EXPECT_EQ(expectedDepthClears, getPerfCounters().depthLoadOpClears); |
| EXPECT_EQ(expectedStencilClears, getPerfCounters().stencilLoadOpClears); |
| |
| // Verify correctness. |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(kSize / 2 - 1, 0, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(kSize / 2 - 1, kSize - 1, GLColor::green); |
| |
| EXPECT_PIXEL_COLOR_EQ(kSize / 2, 0, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(kSize / 2, kSize - 1, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, GLColor::red); |
| } |
| |
| // Tests that scissored clears don't break the RP. |
| TEST_P(VulkanPerformanceCounterTest, ScissoredClearDoesNotBreakRenderPass) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| constexpr GLsizei kSize = 64; |
| |
| GLTexture texture; |
| glBindTexture(GL_TEXTURE_2D, texture); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| |
| GLRenderbuffer renderbuffer; |
| glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, kSize, kSize); |
| |
| GLFramebuffer framebuffer; |
| glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, |
| renderbuffer); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| ASSERT_GL_NO_ERROR(); |
| |
| uint32_t expectedRenderPassCount = getPerfCounters().renderPasses + 1; |
| |
| glEnable(GL_DEPTH_TEST); |
| glEnable(GL_STENCIL_TEST); |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Passthrough(), essl1_shaders::fs::UniformColor()); |
| glUseProgram(program); |
| GLint colorUniformLocation = |
| glGetUniformLocation(program, angle::essl1_shaders::ColorUniform()); |
| ASSERT_NE(-1, colorUniformLocation); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Clear the framebuffer with a draw call to start a render pass. |
| glViewport(0, 0, kSize, kSize); |
| glDepthFunc(GL_ALWAYS); |
| glStencilFunc(GL_ALWAYS, 0x55, 0xFF); |
| glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); |
| glUniform4f(colorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 1.0f); |
| |
| // Issue a scissored clear. |
| glEnable(GL_SCISSOR_TEST); |
| glScissor(kSize / 4, kSize / 4, kSize / 2, kSize / 2); |
| glClearColor(0.0f, 1.0f, 0.0f, 1.0f); |
| glClearDepthf(0.0f); |
| glClearStencil(0x3F); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| // Make sure the render pass wasn't broken. |
| EXPECT_EQ(expectedRenderPassCount, getPerfCounters().renderPasses); |
| |
| // Verify that clear was done correctly. |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, GLColor::red); |
| |
| EXPECT_PIXEL_COLOR_EQ(kSize / 4, kSize / 4, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(3 * kSize / 4 - 1, kSize / 4, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(kSize / 4, 3 * kSize / 4 - 1, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(3 * kSize / 4 - 1, 3 * kSize / 4 - 1, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(kSize / 2, kSize / 2, GLColor::green); |
| |
| glDisable(GL_SCISSOR_TEST); |
| |
| // Make sure the border has depth = 1.0f, stencil = 0x55 |
| glDepthFunc(GL_LESS); |
| glStencilFunc(GL_EQUAL, 0x55, 0xFF); |
| glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); |
| |
| glUniform4f(colorUniformLocation, 0.0f, 0.0f, 1.0f, 1.0f); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.95f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Make sure the center has depth = 0.0f, stencil = 0x3F |
| glDepthFunc(GL_GREATER); |
| glStencilFunc(GL_EQUAL, 0x3F, 0xFF); |
| glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); |
| |
| glUniform4f(colorUniformLocation, 1.0f, 0.0f, 1.0f, 1.0f); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.05f); |
| ASSERT_GL_NO_ERROR(); |
| |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, GLColor::blue); |
| |
| EXPECT_PIXEL_COLOR_EQ(kSize / 4, kSize / 4, GLColor::magenta); |
| EXPECT_PIXEL_COLOR_EQ(3 * kSize / 4 - 1, kSize / 4, GLColor::magenta); |
| EXPECT_PIXEL_COLOR_EQ(kSize / 4, 3 * kSize / 4 - 1, GLColor::magenta); |
| EXPECT_PIXEL_COLOR_EQ(3 * kSize / 4 - 1, 3 * kSize / 4 - 1, GLColor::magenta); |
| EXPECT_PIXEL_COLOR_EQ(kSize / 2, kSize / 2, GLColor::magenta); |
| } |
| |
| // Tests that draw buffer change with all color channel mask off should not break renderpass |
| TEST_P(VulkanPerformanceCounterTest, DrawbufferChangeWithAllColorMaskDisabled) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Passthrough(), essl1_shaders::fs::UniformColor()); |
| glUseProgram(program); |
| GLint colorUniformLocation = |
| glGetUniformLocation(program, angle::essl1_shaders::ColorUniform()); |
| ASSERT_NE(-1, colorUniformLocation); |
| ASSERT_GL_NO_ERROR(); |
| |
| GLTexture textureRGBA; |
| glBindTexture(GL_TEXTURE_2D, textureRGBA); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
| |
| GLTexture textureDepth; |
| glBindTexture(GL_TEXTURE_2D, textureDepth); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, 64, 64, 0, GL_DEPTH_COMPONENT, |
| GL_UNSIGNED_INT, nullptr); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| |
| GLFramebuffer framebuffer; |
| glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureRGBA, 0); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, textureDepth, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| ASSERT_GL_NO_ERROR(); |
| |
| uint32_t expectedRenderPassCount = getPerfCounters().renderPasses + 1; |
| |
| // Draw into FBO |
| glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); |
| glClearColor(0.0f, 1.0f, 0.0f, 1.0f); // clear to green |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
| glViewport(0, 0, 256, 256); |
| glUniform4fv(colorUniformLocation, 1, GLColor::blue.toNormalizedVector().data()); |
| GLenum glDrawBuffers_bufs_1[] = {GL_COLOR_ATTACHMENT0}; |
| glDrawBuffers(1, glDrawBuffers_bufs_1); |
| glEnable(GL_DEPTH_TEST); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| // Change draw buffer state and color mask |
| GLenum glDrawBuffers_bufs_0[] = {GL_NONE}; |
| glDrawBuffers(1, glDrawBuffers_bufs_0); |
| glColorMask(false, false, false, false); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.6f); |
| // Change back draw buffer state and color mask |
| glDrawBuffers(1, glDrawBuffers_bufs_1); |
| glColorMask(true, true, true, true); |
| glUniform4fv(colorUniformLocation, 1, GLColor::red.toNormalizedVector().data()); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.7f); |
| |
| uint32_t actualRenderPassCount = getPerfCounters().renderPasses; |
| EXPECT_EQ(expectedRenderPassCount, actualRenderPassCount); |
| } |
| |
| // Tests the optimization that a glFlush call issued inside a renderpass will be skipped. |
| TEST_P(VulkanPerformanceCounterTest, InRenderpassFlushShouldNotBreakRenderpass) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| uint32_t expectedRenderPassCount = getPerfCounters().renderPasses + 1; |
| |
| GLTexture texture; |
| glBindTexture(GL_TEXTURE_2D, texture); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| |
| GLFramebuffer framebuffer; |
| glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| ASSERT_GL_NO_ERROR(); |
| |
| ANGLE_GL_PROGRAM(redProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); |
| drawQuad(redProgram, essl1_shaders::PositionAttrib(), 0.5f); |
| glFlush(); |
| ANGLE_GL_PROGRAM(greenProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green()); |
| drawQuad(greenProgram, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| |
| uint32_t actualRenderPassCount = getPerfCounters().renderPasses; |
| EXPECT_EQ(expectedRenderPassCount, actualRenderPassCount); |
| } |
| |
| // Tests that depth/stencil texture clear/load works correctly. |
| TEST_P(VulkanPerformanceCounterTest, DepthStencilTextureClearAndLoad) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| // TODO: http://anglebug.com/5329 Flaky test |
| ANGLE_SKIP_TEST_IF(IsWindows() && IsAMD() && IsVulkan()); |
| |
| uint32_t expectedDepthClearCount = getPerfCounters().depthLoadOpClears + 1; |
| uint32_t expectedDepthLoadCount = getPerfCounters().depthLoadOpLoads + 3; |
| uint32_t expectedStencilClearCount = getPerfCounters().stencilLoadOpClears + 1; |
| uint32_t expectedStencilLoadCount = getPerfCounters().stencilLoadOpLoads + 3; |
| |
| constexpr GLsizei kSize = 6; |
| |
| // Create framebuffer to draw into, with both color and depth attachments. |
| GLTexture color; |
| glBindTexture(GL_TEXTURE_2D, color); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| |
| GLTexture depth; |
| glBindTexture(GL_TEXTURE_2D, depth); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, kSize, kSize, 0, GL_DEPTH_STENCIL, |
| GL_UNSIGNED_INT_24_8_OES, nullptr); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color, 0); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, depth, 0); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Set up texture for copy operation that breaks the render pass |
| GLTexture copyTex; |
| glBindTexture(GL_TEXTURE_2D, copyTex); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| |
| // Set viewport and clear depth/stencil |
| glViewport(0, 0, kSize, kSize); |
| glClearDepthf(1); |
| glClearStencil(0x55); |
| glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| // If depth is not cleared to 1, rendering would fail. |
| glEnable(GL_DEPTH_TEST); |
| glDepthFunc(GL_LESS); |
| glDepthMask(GL_FALSE); |
| |
| // If stencil is not clear to 0x55, rendering would fail. |
| glEnable(GL_STENCIL_TEST); |
| glStencilFunc(GL_EQUAL, 0x55, 0xFF); |
| glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); |
| glStencilMask(0xFF); |
| |
| // Set up program |
| ANGLE_GL_PROGRAM(drawColor, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor()); |
| glUseProgram(drawColor); |
| GLint colorUniformLocation = |
| glGetUniformLocation(drawColor, angle::essl1_shaders::ColorUniform()); |
| ASSERT_NE(colorUniformLocation, -1); |
| |
| // Draw red |
| glUniform4f(colorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f); |
| drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Break the render pass |
| glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, kSize / 2, kSize / 2); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Draw green |
| glUniform4f(colorUniformLocation, 0.0f, 1.0f, 0.0f, 1.0f); |
| drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Break the render pass |
| glCopyTexSubImage2D(GL_TEXTURE_2D, 0, kSize / 2, 0, 0, 0, kSize / 2, kSize / 2); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Draw blue |
| glUniform4f(colorUniformLocation, 0.0f, 0.0f, 1.0f, 1.0f); |
| drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Break the render pass |
| glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, kSize / 2, 0, 0, kSize / 2, kSize / 2); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Draw yellow |
| glUniform4f(colorUniformLocation, 1.0f, 1.0f, 0.0f, 1.0f); |
| drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Break the render pass |
| glCopyTexSubImage2D(GL_TEXTURE_2D, 0, kSize / 2, kSize / 2, 0, 0, kSize / 2, kSize / 2); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Verify the counters |
| EXPECT_EQ(getPerfCounters().depthLoadOpClears, expectedDepthClearCount); |
| EXPECT_EQ(getPerfCounters().depthLoadOpLoads, expectedDepthLoadCount); |
| EXPECT_EQ(getPerfCounters().stencilLoadOpClears, expectedStencilClearCount); |
| EXPECT_EQ(getPerfCounters().stencilLoadOpLoads, expectedStencilLoadCount); |
| |
| // Verify that copies were done correctly. |
| GLFramebuffer verifyFBO; |
| glBindFramebuffer(GL_FRAMEBUFFER, verifyFBO); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, copyTex, 0); |
| |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(kSize / 2, 0, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(0, kSize / 2, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(kSize / 2, kSize / 2, GLColor::yellow); |
| } |
| |
| // Tests that multisampled-render-to-texture depth/stencil textures don't ever load data. |
| TEST_P(VulkanPerformanceCounterTest, RenderToTextureDepthStencilTextureShouldNotLoad) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| // http://anglebug.com/5083 |
| ANGLE_SKIP_TEST_IF(IsWindows() && IsAMD() && IsVulkan()); |
| |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture2")); |
| |
| uint32_t expectedDepthClearCount = getPerfCounters().depthLoadOpClears + 1; |
| uint32_t expectedDepthLoadCount = getPerfCounters().depthLoadOpLoads; |
| uint32_t expectedStencilClearCount = getPerfCounters().stencilLoadOpClears + 1; |
| uint32_t expectedStencilLoadCount = getPerfCounters().stencilLoadOpLoads; |
| |
| constexpr GLsizei kSize = 6; |
| |
| // Create multisampled framebuffer to draw into, with both color and depth attachments. |
| GLTexture colorMS; |
| glBindTexture(GL_TEXTURE_2D, colorMS); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| |
| GLTexture depthMS; |
| glBindTexture(GL_TEXTURE_2D, depthMS); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, kSize, kSize, 0, GL_DEPTH_STENCIL, |
| GL_UNSIGNED_INT_24_8_OES, nullptr); |
| |
| GLFramebuffer fboMS; |
| glBindFramebuffer(GL_FRAMEBUFFER, fboMS); |
| glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, |
| colorMS, 0, 4); |
| glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, |
| depthMS, 0, 4); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Set up texture for copy operation that breaks the render pass |
| GLTexture copyTex; |
| glBindTexture(GL_TEXTURE_2D, copyTex); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| |
| // Set viewport and clear depth |
| glViewport(0, 0, kSize, kSize); |
| glClearDepthf(1); |
| glClearStencil(0x55); |
| glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| // If depth is not cleared to 1, rendering would fail. |
| glEnable(GL_DEPTH_TEST); |
| glDepthFunc(GL_LESS); |
| |
| // If stencil is not clear to 0x55, rendering would fail. |
| glEnable(GL_STENCIL_TEST); |
| glStencilFunc(GL_EQUAL, 0x55, 0xFF); |
| glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); |
| glStencilMask(0xFF); |
| |
| // Set up program |
| ANGLE_GL_PROGRAM(drawColor, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor()); |
| glUseProgram(drawColor); |
| GLint colorUniformLocation = |
| glGetUniformLocation(drawColor, angle::essl1_shaders::ColorUniform()); |
| ASSERT_NE(colorUniformLocation, -1); |
| |
| // Draw red |
| glUniform4f(colorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f); |
| drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Break the render pass |
| glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, kSize / 2, kSize / 2); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Draw green |
| glUniform4f(colorUniformLocation, 0.0f, 1.0f, 0.0f, 1.0f); |
| drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Break the render pass |
| glCopyTexSubImage2D(GL_TEXTURE_2D, 0, kSize / 2, 0, 0, 0, kSize / 2, kSize / 2); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Draw blue |
| glUniform4f(colorUniformLocation, 0.0f, 0.0f, 1.0f, 1.0f); |
| drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Break the render pass |
| glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, kSize / 2, 0, 0, kSize / 2, kSize / 2); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Draw yellow |
| glUniform4f(colorUniformLocation, 1.0f, 1.0f, 0.0f, 1.0f); |
| drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Break the render pass |
| glCopyTexSubImage2D(GL_TEXTURE_2D, 0, kSize / 2, kSize / 2, 0, 0, kSize / 2, kSize / 2); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Verify the counters |
| EXPECT_EQ(getPerfCounters().depthLoadOpClears, expectedDepthClearCount); |
| EXPECT_EQ(getPerfCounters().depthLoadOpLoads, expectedDepthLoadCount); |
| EXPECT_EQ(getPerfCounters().stencilLoadOpClears, expectedStencilClearCount); |
| EXPECT_EQ(getPerfCounters().stencilLoadOpLoads, expectedStencilLoadCount); |
| |
| // Verify that copies were done correctly. Only the first copy can be verified because the |
| // contents of the depth/stencil buffer is undefined after the first render pass break, meaning |
| // it is unknown whether the three subsequent draw calls passed the depth or stencil tests. |
| GLFramebuffer verifyFBO; |
| glBindFramebuffer(GL_FRAMEBUFFER, verifyFBO); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, copyTex, 0); |
| |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(kSize / 2 - 1, 0, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(0, kSize / 2 - 1, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(kSize / 2 - 1, kSize / 2 - 1, GLColor::red); |
| } |
| |
| // Tests that multisampled-render-to-texture depth/stencil renderbuffers don't ever load depth data. |
| // Stencil data may still be loaded if VK_EXT_shader_stencil_export is not supported. |
| TEST_P(VulkanPerformanceCounterTest, RenderToTextureDepthStencilRenderbufferShouldNotLoad) |
| { |
| // http://anglebug.com/5083 |
| ANGLE_SKIP_TEST_IF(IsWindows() && IsAMD() && IsVulkan()); |
| // http://anglebug.com/5380 |
| ANGLE_SKIP_TEST_IF(IsLinux() && IsAMD() && IsVulkan()); |
| |
| // http://crbug.com/1134286 |
| ANGLE_SKIP_TEST_IF(IsWindows7() && IsNVIDIA() && IsVulkan()); |
| |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture")); |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| angle::VulkanPerfCounters expected; |
| |
| // This test creates 4 render passes. In the first render pass, color, depth and stencil are |
| // cleared. In the following render passes, they must be loaded. However, given that the |
| // attachments are multisampled-render-to-texture, loads are done through an unresolve |
| // operation. All 4 render passes resolve the attachments. |
| |
| // Expect rpCount+4, depth(Clears+1, Loads+3, LoadNones+0, Stores+3, StoreNones+0), |
| // stencil(Clears+1, Loads+3, LoadNones+0, Stores+3, StoreNones+0). Note that the Loads and |
| // Stores are from the resolve attachments. |
| setExpectedCountersForDepthOps(getPerfCounters(), 4, 1, 3, 0, 3, 0, &expected); |
| setExpectedCountersForStencilOps(getPerfCounters(), 1, 3, 0, 3, 0, &expected); |
| |
| // Additionally, expect 4 resolves and 3 unresolves. |
| setExpectedCountersForUnresolveResolveTest(getPerfCounters(), 3, 3, 3, 4, 4, 4, &expected); |
| |
| constexpr GLsizei kSize = 6; |
| |
| // Create multisampled framebuffer to draw into, with both color and depth attachments. |
| GLTexture colorMS; |
| glBindTexture(GL_TEXTURE_2D, colorMS); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| |
| GLRenderbuffer depthStencilMS; |
| glBindRenderbuffer(GL_RENDERBUFFER, depthStencilMS); |
| glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, kSize, kSize); |
| |
| GLFramebuffer fboMS; |
| glBindFramebuffer(GL_FRAMEBUFFER, fboMS); |
| glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, |
| colorMS, 0, 4); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, |
| depthStencilMS); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Set up texture for copy operation that breaks the render pass |
| GLTexture copyTex; |
| glBindTexture(GL_TEXTURE_2D, copyTex); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| |
| // Set viewport and clear color, depth and stencil |
| glViewport(0, 0, kSize, kSize); |
| glClearDepthf(1); |
| glClearStencil(0x55); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| // If depth is not cleared to 1, rendering would fail. |
| glEnable(GL_DEPTH_TEST); |
| glDepthFunc(GL_LESS); |
| |
| // If stencil is not clear to 0x55, rendering would fail. |
| glEnable(GL_STENCIL_TEST); |
| glStencilFunc(GL_EQUAL, 0x55, 0xFF); |
| glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); |
| glStencilMask(0xFF); |
| |
| // Set up program |
| ANGLE_GL_PROGRAM(drawColor, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor()); |
| glUseProgram(drawColor); |
| GLint colorUniformLocation = |
| glGetUniformLocation(drawColor, angle::essl1_shaders::ColorUniform()); |
| ASSERT_NE(colorUniformLocation, -1); |
| |
| // Draw red |
| glUniform4f(colorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f); |
| drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.75f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Break the render pass |
| glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, kSize / 2, kSize / 2); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Draw green |
| glUniform4f(colorUniformLocation, 0.0f, 1.0f, 0.0f, 1.0f); |
| drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Break the render pass |
| glCopyTexSubImage2D(GL_TEXTURE_2D, 0, kSize / 2, 0, 0, 0, kSize / 2, kSize / 2); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Draw blue |
| glUniform4f(colorUniformLocation, 0.0f, 0.0f, 1.0f, 1.0f); |
| drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.25f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Break the render pass |
| glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, kSize / 2, 0, 0, kSize / 2, kSize / 2); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Draw yellow |
| glUniform4f(colorUniformLocation, 1.0f, 1.0f, 0.0f, 1.0f); |
| drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Break the render pass |
| glCopyTexSubImage2D(GL_TEXTURE_2D, 0, kSize / 2, kSize / 2, 0, 0, kSize / 2, kSize / 2); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Verify the counters |
| compareDepthStencilLoadOpCounters(getPerfCounters(), expected); |
| compareCountersForUnresolveResolveTest(getPerfCounters(), expected); |
| |
| // Verify that copies were done correctly. |
| GLFramebuffer verifyFBO; |
| glBindFramebuffer(GL_FRAMEBUFFER, verifyFBO); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, copyTex, 0); |
| |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(kSize / 2, 0, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(0, kSize / 2, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(kSize / 2, kSize / 2, GLColor::yellow); |
| } |
| |
| // Tests counters when multisampled-render-to-texture color/depth/stencil renderbuffers are |
| // invalidated. |
| TEST_P(VulkanPerformanceCounterTest, RenderToTextureInvalidate) |
| { |
| // http://anglebug.com/5083 |
| ANGLE_SKIP_TEST_IF(IsWindows() && IsAMD() && IsVulkan()); |
| |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture")); |
| |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| angle::VulkanPerfCounters expected; |
| |
| // This test creates 4 render passes. In the first render pass, color, depth and stencil are |
| // cleared. After every render pass, the attachments are invalidated. In the following render |
| // passes thus they are not loaded (rather unresolved, as the attachments are |
| // multisampled-render-to-texture). Due to the invalidate call, neither of the 4 render passes |
| // should resolve the attachments. |
| |
| // Expect rpCount+4, color(Clears+1, Loads+0, LoadNones+0, Stores+0, StoreNones+0) |
| setExpectedCountersForColorOps(getPerfCounters(), 4, 1, 0, 0, 0, 0, &expected); |
| // Expect rpCount+4, depth(Clears+1, Loads+0, LoadNones+0, Stores+0, StoreNones+0), |
| // stencil(Clears+1, Loads+0, LoadNones+0, Stores+0, StoreNones+0) |
| setExpectedCountersForDepthOps(getPerfCounters(), 4, 1, 0, 0, 0, 0, &expected); |
| setExpectedCountersForStencilOps(getPerfCounters(), 1, 0, 0, 0, 0, &expected); |
| |
| // Additionally, expect no resolve and unresolve. |
| setExpectedCountersForUnresolveResolveTest(getPerfCounters(), 0, 0, 0, 0, 0, 0, &expected); |
| |
| constexpr GLsizei kSize = 6; |
| |
| // Create multisampled framebuffer to draw into, with both color and depth attachments. |
| GLTexture colorMS; |
| glBindTexture(GL_TEXTURE_2D, colorMS); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| |
| GLRenderbuffer depthStencilMS; |
| glBindRenderbuffer(GL_RENDERBUFFER, depthStencilMS); |
| glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, kSize, kSize); |
| |
| GLFramebuffer fboMS; |
| glBindFramebuffer(GL_FRAMEBUFFER, fboMS); |
| glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, |
| colorMS, 0, 4); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, |
| depthStencilMS); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Set up texture for copy operation that breaks the render pass |
| GLTexture copyTex; |
| glBindTexture(GL_TEXTURE_2D, copyTex); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| |
| // Set viewport and clear color, depth and stencil |
| glViewport(0, 0, kSize, kSize); |
| glClearColor(0, 0, 0, 1.0f); |
| glClearDepthf(1); |
| glClearStencil(0x55); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| // Output depth/stencil, but disable testing so all draw calls succeed |
| glEnable(GL_DEPTH_TEST); |
| glDepthFunc(GL_ALWAYS); |
| |
| glEnable(GL_STENCIL_TEST); |
| glStencilFunc(GL_ALWAYS, 0x55, 0xFF); |
| glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); |
| glStencilMask(0xFF); |
| |
| // Set up program |
| ANGLE_GL_PROGRAM(drawColor, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor()); |
| glUseProgram(drawColor); |
| GLint colorUniformLocation = |
| glGetUniformLocation(drawColor, angle::essl1_shaders::ColorUniform()); |
| ASSERT_NE(colorUniformLocation, -1); |
| |
| // Draw red |
| glUniform4f(colorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f); |
| drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.75f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Invalidate everything |
| const GLenum discards[] = {GL_COLOR_ATTACHMENT0, GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT}; |
| glInvalidateFramebuffer(GL_FRAMEBUFFER, 3, discards); |
| |
| // Break the render pass |
| glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, kSize / 2, kSize / 2); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Draw green |
| glUniform4f(colorUniformLocation, 0.0f, 1.0f, 0.0f, 1.0f); |
| drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Invalidate everything |
| glInvalidateFramebuffer(GL_FRAMEBUFFER, 3, discards); |
| |
| // Break the render pass |
| glCopyTexSubImage2D(GL_TEXTURE_2D, 0, kSize / 2, 0, 0, 0, kSize / 2, kSize / 2); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Draw blue |
| glUniform4f(colorUniformLocation, 0.0f, 0.0f, 1.0f, 1.0f); |
| drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.25f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Invalidate everything |
| glInvalidateFramebuffer(GL_FRAMEBUFFER, 3, discards); |
| |
| // Break the render pass |
| glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, kSize / 2, 0, 0, kSize / 2, kSize / 2); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Draw yellow |
| glUniform4f(colorUniformLocation, 1.0f, 1.0f, 0.0f, 1.0f); |
| drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.0f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Invalidate everything |
| glInvalidateFramebuffer(GL_FRAMEBUFFER, 3, discards); |
| |
| // Break the render pass |
| glCopyTexSubImage2D(GL_TEXTURE_2D, 0, kSize / 2, kSize / 2, 0, 0, kSize / 2, kSize / 2); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Verify the counters |
| compareColorOpCounters(getPerfCounters(), expected); |
| compareDepthStencilOpCounters(getPerfCounters(), expected); |
| compareCountersForUnresolveResolveTest(getPerfCounters(), expected); |
| } |
| |
| // Tests counters when uninitialized multisampled-render-to-texture depth/stencil renderbuffers are |
| // unused but not invalidated. |
| TEST_P(VulkanPerformanceCounterTest, RenderToTextureUninitializedAndUnusedDepthStencil) |
| { |
| // http://anglebug.com/5083 |
| ANGLE_SKIP_TEST_IF(IsWindows() && IsAMD() && IsVulkan()); |
| |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture")); |
| |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| angle::VulkanPerfCounters expected; |
| |
| // Expect rpCount+1, no depth/stencil clear, load or store. |
| setExpectedCountersForDepthOps(getPerfCounters(), 1, 0, 0, 0, 0, 0, &expected); |
| setExpectedCountersForStencilOps(getPerfCounters(), 0, 0, 0, 0, 0, &expected); |
| |
| // Additionally, expect only color resolve. |
| setExpectedCountersForUnresolveResolveTest(getPerfCounters(), 0, 0, 0, 1, 0, 0, &expected); |
| |
| constexpr GLsizei kSize = 6; |
| |
| // Create multisampled framebuffer to draw into, with both color and depth attachments. |
| GLTexture colorMS; |
| glBindTexture(GL_TEXTURE_2D, colorMS); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| |
| GLRenderbuffer depthStencilMS; |
| glBindRenderbuffer(GL_RENDERBUFFER, depthStencilMS); |
| glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, kSize, kSize); |
| |
| GLFramebuffer fboMS; |
| glBindFramebuffer(GL_FRAMEBUFFER, fboMS); |
| glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, |
| colorMS, 0, 4); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, |
| depthStencilMS); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Set up texture for copy operation that breaks the render pass |
| GLTexture copyTex; |
| glBindTexture(GL_TEXTURE_2D, copyTex); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| |
| // Set viewport and clear color only |
| glViewport(0, 0, kSize, kSize); |
| glClearColor(0, 0, 0, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| // Disable depth/stencil testing. |
| glDisable(GL_DEPTH_TEST); |
| glDisable(GL_STENCIL_TEST); |
| |
| // Set up program |
| ANGLE_GL_PROGRAM(drawColor, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor()); |
| glUseProgram(drawColor); |
| GLint colorUniformLocation = |
| glGetUniformLocation(drawColor, angle::essl1_shaders::ColorUniform()); |
| ASSERT_NE(colorUniformLocation, -1); |
| |
| // Draw red |
| glUniform4f(colorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f); |
| drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.75f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Break the render pass |
| glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, kSize / 2, kSize / 2); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Verify the counters |
| compareDepthStencilLoadOpCounters(getPerfCounters(), expected); |
| compareCountersForUnresolveResolveTest(getPerfCounters(), expected); |
| } |
| |
| // Ensures we use read-only depth layout when there is no write |
| TEST_P(VulkanPerformanceCounterTest, ReadOnlyDepthBufferLayout) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| constexpr GLsizei kSize = 64; |
| |
| angle::VulkanPerfCounters expected; |
| |
| // Create depth only FBO and fill depth texture to leftHalf=0.0 and rightHalf=1.0. This should |
| // use writeable layout |
| expected.readOnlyDepthStencilRenderPasses = getPerfCounters().readOnlyDepthStencilRenderPasses; |
| |
| // Expect rpCount+1, depth(Clears+0, Loads+0, LoadNones+0, Stores+1, StoreNones+0), |
| // stencil(Clears+0, Loads+0, LoadNones+0, Stores+0, StoreNones+0) |
| setExpectedCountersForDepthOps(getPerfCounters(), 1, 0, 0, 0, 1, 0, &expected); |
| setExpectedCountersForStencilOps(getPerfCounters(), 0, 0, 0, 0, 0, &expected); |
| |
| GLTexture depthTexture; |
| glBindTexture(GL_TEXTURE_2D, depthTexture); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, kSize, kSize, 0, GL_DEPTH_COMPONENT, |
| GL_UNSIGNED_INT, nullptr); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| |
| GLFramebuffer depthOnlyFBO; |
| glBindFramebuffer(GL_FRAMEBUFFER, depthOnlyFBO); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTexture, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| glEnable(GL_DEPTH_TEST); |
| glDepthFunc(GL_ALWAYS); |
| glDepthMask(GL_TRUE); |
| ANGLE_GL_PROGRAM(redProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); |
| glViewport(0, 0, kSize / 2, kSize); |
| drawQuad(redProgram, essl1_shaders::PositionAttrib(), 0.0f); |
| glViewport(kSize / 2, 0, kSize / 2, kSize); |
| drawQuad(redProgram, essl1_shaders::PositionAttrib(), 1.0f); |
| glViewport(0, 0, kSize, kSize); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Because the layout counter is updated at end of renderpass, we need to issue a finish call |
| // here to end the renderpass. |
| glFinish(); |
| |
| uint32_t actualReadOnlyDepthStencilCount = getPerfCounters().readOnlyDepthStencilRenderPasses; |
| EXPECT_EQ(expected.readOnlyDepthStencilRenderPasses, actualReadOnlyDepthStencilCount); |
| compareDepthStencilOpCounters(getPerfCounters(), expected); |
| |
| // Create a color+depth FBO and use depth as read only. This should use read only layout |
| ++expected.readOnlyDepthStencilRenderPasses; |
| // Expect rpCount+1, depth(Clears+0, Loads+1, LoadNones+0, Stores+0, StoreNones+1), |
| setExpectedCountersForDepthOps(getPerfCounters(), 1, 0, 1, 0, 0, 1, &expected); |
| |
| GLTexture colorTexture; |
| glBindTexture(GL_TEXTURE_2D, colorTexture); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| GLFramebuffer depthAndColorFBO; |
| glBindFramebuffer(GL_FRAMEBUFFER, depthAndColorFBO); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture, 0); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTexture, 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| // Clear color to blue and draw a green quad with depth=0.5 |
| glEnable(GL_DEPTH_TEST); |
| glDepthFunc(GL_LESS); |
| glDepthMask(GL_FALSE); |
| |
| angle::Vector4 clearColor = GLColor::blue.toNormalizedVector(); |
| glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]); |
| glClear(GL_COLOR_BUFFER_BIT); |
| drawQuad(redProgram, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| // The pixel check will end renderpass. |
| EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(1 + kSize / 2, 1, GLColor::red); |
| actualReadOnlyDepthStencilCount = getPerfCounters().readOnlyDepthStencilRenderPasses; |
| EXPECT_EQ(expected.readOnlyDepthStencilRenderPasses, actualReadOnlyDepthStencilCount); |
| compareDepthStencilOpCounters(getPerfCounters(), expected); |
| } |
| |
| // Ensures depth/stencil is not loaded after storeOp=DONT_CARE due to optimization (as opposed to |
| // invalidate) |
| TEST_P(VulkanPerformanceCounterTest, RenderPassAfterRenderPassWithoutDepthStencilWrite) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| angle::VulkanPerfCounters expected; |
| |
| // Expect rpCount+1, depth(Clears+0, Loads+0, LoadNones+0, Stores+0, StoreNones+0), |
| // stencil(Clears+0, Loads+0, LoadNones+0, Stores+0, StoreNones+0) |
| setExpectedCountersForDepthOps(getPerfCounters(), 1, 0, 0, 0, 0, 0, &expected); |
| setExpectedCountersForStencilOps(getPerfCounters(), 0, 0, 0, 0, 0, &expected); |
| |
| constexpr GLsizei kSize = 64; |
| |
| // Create FBO with color, depth and stencil. Leave depth/stencil uninitialized. |
| GLTexture texture; |
| glBindTexture(GL_TEXTURE_2D, texture); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| |
| GLRenderbuffer renderbuffer; |
| glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, kSize, kSize); |
| |
| GLFramebuffer framebuffer; |
| glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, |
| renderbuffer); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Draw to the FBO, without enabling depth/stencil. |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Passthrough(), essl1_shaders::fs::UniformColor()); |
| glUseProgram(program); |
| GLint colorUniformLocation = |
| glGetUniformLocation(program, angle::essl1_shaders::ColorUniform()); |
| ASSERT_NE(-1, colorUniformLocation); |
| ASSERT_GL_NO_ERROR(); |
| |
| glViewport(0, 0, kSize, kSize); |
| glUniform4f(colorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 1.0f); |
| |
| // Break the render pass and ensure no depth/stencil load/store was done. |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| compareDepthStencilOpCounters(getPerfCounters(), expected); |
| |
| // Expect rpCount+1, depth(Clears+0, Loads+0, LoadNones+0, Stores+0, StoreNones+0), |
| // stencil(Clears+0, Loads+0, LoadNones+0, Stores+0, StoreNones+0) |
| setExpectedCountersForDepthOps(getPerfCounters(), 1, 0, 0, 0, 0, 0, &expected); |
| setExpectedCountersForStencilOps(getPerfCounters(), 0, 0, 0, 0, 0, &expected); |
| |
| // Draw again with similar conditions, and again make sure no load/store is done. |
| glUniform4f(colorUniformLocation, 0.0f, 1.0f, 0.0f, 1.0f); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 1.0f); |
| |
| // Break the render pass and ensure no depth/stencil load/store was done. |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| compareDepthStencilOpCounters(getPerfCounters(), expected); |
| |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| } |
| |
| // Ensures repeated clears of various kind (all attachments, some attachments, scissored, masked |
| // etc) don't break the render pass. |
| TEST_P(VulkanPerformanceCounterTest, ClearAfterClearDoesNotBreakRenderPass) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| uint32_t expectedRenderPassCount = getPerfCounters().renderPasses + 1; |
| |
| constexpr GLsizei kSize = 6; |
| |
| // Create a framebuffer to clear with both color and depth/stencil attachments. |
| GLTexture color; |
| glBindTexture(GL_TEXTURE_2D, color); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| |
| GLTexture depth; |
| glBindTexture(GL_TEXTURE_2D, depth); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, kSize, kSize, 0, GL_DEPTH_STENCIL, |
| GL_UNSIGNED_INT_24_8_OES, nullptr); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color, 0); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, depth, 0); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Clear color and depth, but not stencil. |
| glClearColor(0.0f, 0.0f, 0.0f, 0.0f); |
| glClearDepthf(0.0f); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
| |
| // Clear color and stencil, but not depth. |
| glClearColor(1.0f, 0.0f, 0.0f, 0.0f); |
| glClearStencil(0x11); |
| glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| // Clear depth and stencil, but not color. |
| glClearDepthf(0.1f); |
| glClearStencil(0x22); |
| glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| // Clear masked color, and unmasked depth. |
| glClearDepthf(0.2f); |
| glClearColor(0.1f, 1.0f, 0.0f, 1.0f); |
| glColorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_FALSE); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
| |
| // Clear unmasked color, and masked stencil. |
| glClearColor(0.0f, 0.0f, 1.0f, 1.0f); |
| glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); |
| glClearStencil(0x33); |
| glStencilMask(0xF0); |
| glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| // Clear unmasked depth and stencil. |
| glClearDepthf(0.3f); |
| glClearStencil(0x44); |
| glStencilMask(0xFF); |
| glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| // Clear with scissor. |
| glEnable(GL_SCISSOR_TEST); |
| glScissor(kSize / 3, kSize / 3, kSize / 3, kSize / 3); |
| glClearColor(1.0f, 0.0f, 0.0f, 1.0f); |
| glClearDepthf(1.0f); |
| glClearStencil(0x55); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| // Verify render pass count. |
| EXPECT_EQ(getPerfCounters().renderPasses, expectedRenderPassCount); |
| |
| // Make sure the result is correct. The border of the image should be blue with depth 0.3f and |
| // stencil 0x44. The center is red with depth 1.0f and stencil 0x55. |
| |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, GLColor::blue); |
| |
| EXPECT_PIXEL_COLOR_EQ(kSize / 3, kSize / 3, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(2 * kSize / 3 - 1, kSize / 3, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(kSize / 3, 2 * kSize / 3 - 1, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(2 * kSize / 3 - 1, 2 * kSize / 3 - 1, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(kSize / 2, kSize / 2, GLColor::red); |
| |
| glViewport(0, 0, kSize, kSize); |
| glDisable(GL_SCISSOR_TEST); |
| |
| // Center: If depth is not cleared to 1, rendering would fail. |
| glEnable(GL_DEPTH_TEST); |
| glDepthFunc(GL_LESS); |
| |
| // Center: If stencil is not clear to 0x55, rendering would fail. |
| glEnable(GL_STENCIL_TEST); |
| glStencilFunc(GL_EQUAL, 0x55, 0xFF); |
| glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); |
| glStencilMask(0xFF); |
| |
| // Set up program |
| ANGLE_GL_PROGRAM(drawColor, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor()); |
| glUseProgram(drawColor); |
| GLint colorUniformLocation = |
| glGetUniformLocation(drawColor, angle::essl1_shaders::ColorUniform()); |
| ASSERT_NE(colorUniformLocation, -1); |
| |
| // Draw green |
| glUniform4f(colorUniformLocation, 0.0f, 1.0f, 0.0f, 1.0f); |
| drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.95f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Verify that only the center has changed |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, GLColor::blue); |
| |
| EXPECT_PIXEL_COLOR_EQ(kSize / 3, kSize / 3, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(2 * kSize / 3 - 1, kSize / 3, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(kSize / 3, 2 * kSize / 3 - 1, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(2 * kSize / 3 - 1, 2 * kSize / 3 - 1, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(kSize / 2, kSize / 2, GLColor::green); |
| |
| // Border: If depth is not cleared to 0.3f, rendering would fail. |
| glDepthFunc(GL_LESS); |
| |
| // Center: If stencil is not clear to 0x44, rendering would fail. |
| glStencilFunc(GL_EQUAL, 0x44, 0xFF); |
| |
| // Draw yellow |
| glUniform4f(colorUniformLocation, 1.0f, 1.0f, 0.0f, 1.0f); |
| drawQuad(drawColor, essl1_shaders::PositionAttrib(), -0.5f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Verify that only the border has changed |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, GLColor::yellow); |
| EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, GLColor::yellow); |
| EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, GLColor::yellow); |
| |
| EXPECT_PIXEL_COLOR_EQ(kSize / 3, kSize / 3, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(2 * kSize / 3 - 1, kSize / 3, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(kSize / 3, 2 * kSize / 3 - 1, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(2 * kSize / 3 - 1, 2 * kSize / 3 - 1, GLColor::green); |
| EXPECT_PIXEL_COLOR_EQ(kSize / 2, kSize / 2, GLColor::green); |
| } |
| |
| // Ensures that changing the scissor size doesn't break the render pass. |
| TEST_P(VulkanPerformanceCounterTest, ScissorDoesNotBreakRenderPass) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| constexpr GLsizei kSize = 16; |
| |
| // Create a framebuffer with a color attachment. |
| GLTexture color; |
| glBindTexture(GL_TEXTURE_2D, color); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color, 0); |
| ASSERT_GL_NO_ERROR(); |
| |
| // First, issue a clear and make sure it's done. Later we can verify that areas outside |
| // scissors are not rendered to. |
| glClearColor(0, 0, 0, 1); |
| glClear(GL_COLOR_BUFFER_BIT); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black); |
| |
| uint32_t expectedRenderPassCount = getPerfCounters().renderPasses + 1; |
| |
| // This test starts with a small scissor and gradually grows it and issues draw calls and |
| // various kinds of clears: |
| // |
| // - Clear the center to red |
| // |
| // +----------------------+ |
| // | K | |
| // | | |
| // | +-----+ | |
| // | | | | |
| // | | R | | |
| // | | | | |
| // | +-----+ | |
| // | | |
| // | | |
| // | | |
| // | | |
| // +----------------------+ |
| // |
| // - Draw green to center right |
| // |
| // +----------------------+ |
| // | | |
| // | +-------+ |
| // | +-----+| | |
| // | | || | |
| // | | R || G | |
| // | | || | |
| // | +-----+| | |
| // | | | |
| // | | | |
| // | | | |
| // | +-------+ |
| // +----------------------+ |
| // |
| // - Masked clear of center column, only outputting to the blue channel |
| // |
| // +----------------------+ |
| // | +---+ | |
| // | | B | +-------+ |
| // | |+--+--+| | |
| // | || | || | |
| // | ||M |R || G | |
| // | || | || | |
| // | |+--+--+| | |
| // | | | | | |
| // | | | | | |
| // | | | | | |
| // | | | +-------+ |
| // +------+---+-----------+ |
| // |
| // - Masked draw of center row, only outputting to alpha. |
| // |
| // +----------------------+ |
| // | K +---+ K | |
| // | | B | +-------+ |
| // | |+--+--+| | |
| // | ||M |R || G | |
| // | +----++--+--++-----+ | |
| // | | ||TM|TR|| | | |
| // | | TK |+--+--+| TG | | |
| // | | |TB |TK | | | |
| // | +----+---+---+-----+ | |
| // | | | | G | |
| // | K | B | K +-------+ |
| // +------+---+-----------+ |
| // |
| // Where: K=Black, R=Red, G=Green, B=Blue, M=Magenta, T=Transparent |
| |
| constexpr GLsizei kClearX = kSize / 3; |
| constexpr GLsizei kClearY = kSize / 3; |
| constexpr GLsizei kClearWidth = kSize / 3; |
| constexpr GLsizei kClearHeight = kSize / 3; |
| |
| constexpr GLsizei kDrawX = kClearX + kClearWidth + 2; |
| constexpr GLsizei kDrawY = kSize / 5; |
| constexpr GLsizei kDrawWidth = kSize - kDrawX; |
| constexpr GLsizei kDrawHeight = 7 * kSize / 10; |
| |
| constexpr GLsizei kMaskedClearX = kSize / 4; |
| constexpr GLsizei kMaskedClearY = kSize / 8; |
| constexpr GLsizei kMaskedClearWidth = kSize / 4; |
| constexpr GLsizei kMaskedClearHeight = 7 * kSize / 8; |
| |
| constexpr GLsizei kMaskedDrawX = kSize / 8; |
| constexpr GLsizei kMaskedDrawY = kSize / 2; |
| constexpr GLsizei kMaskedDrawWidth = 6 * kSize / 8; |
| constexpr GLsizei kMaskedDrawHeight = kSize / 4; |
| |
| glEnable(GL_SCISSOR_TEST); |
| |
| // Clear center to red |
| glScissor(kClearX, kClearY, kClearWidth, kClearHeight); |
| glClearColor(1.0f, 0.0f, 0.0f, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| ANGLE_GL_PROGRAM(drawColor, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor()); |
| glUseProgram(drawColor); |
| GLint colorUniformLocation = |
| glGetUniformLocation(drawColor, angle::essl1_shaders::ColorUniform()); |
| ASSERT_NE(colorUniformLocation, -1); |
| |
| // Draw green to center right |
| glScissor(kDrawX, kDrawY, kDrawWidth, kDrawHeight); |
| glUniform4f(colorUniformLocation, 0.0f, 1.0f, 0.0f, 1.0f); |
| drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Masked blue-channel clear of center column |
| glColorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_FALSE); |
| glScissor(kMaskedClearX, kMaskedClearY, kMaskedClearWidth, kMaskedClearHeight); |
| glClearColor(0.5f, 0.5f, 1.0f, 0.5f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| // Masked alpha-channel draw of center row |
| glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE); |
| glScissor(kMaskedDrawX, kMaskedDrawY, kMaskedDrawWidth, kMaskedDrawHeight); |
| glUniform4f(colorUniformLocation, 0.5f, 0.5f, 0.5f, 0.0f); |
| drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Verify render pass count. |
| EXPECT_EQ(getPerfCounters().renderPasses, expectedRenderPassCount); |
| |
| // Make sure the result is correct: |
| // |
| // +----------------------+ <-- 0 |
| // | K +---+ K | <-- kMaskedClearY |
| // | | B | +-------+ <-- kDrawY |
| // | |+--+--+| | <-- kClearY |
| // | ||M |R || G | |
| // | +----++--+--++-----+ | <-- kMaskedDrawY |
| // | | ||TM|TR|| | | |
| // | | TK |+--+--+| TG | | <-- kClearY + kClearHeight |
| // | | |TB |TK | | | |
| // | +----+---+---+-----+ | <-- kMaskedDrawY + kMaskedDrawHeight |
| // | | | | G | |
| // | K | B | K +-------+ <-- kDrawY + kDrawHeight |
| // +------+---+-----------+ <-- kSize == kMaskedClearY + kMaskedClearHeight |
| // | | || | || | | |
| // | | || | || | \---> kSize == kDrawX + kDrawWidth |
| // | | || | || \-----> kMaskedDrawX + kMaskedDrawWidth |
| // | | || | | \-----------> kDrawX |
| // | | || | \------------> kClearX + kClearWidth |
| // | | || \---------------> kMaskedClearX + kMaskedClearWidth |
| // | | | \------------------> kClearX |
| // | | \-------------------> kMaskedClearX |
| // | \------------------------> kMaskedDrawX |
| // \--------------------------> 0 |
| |
| constexpr GLsizei kClearX2 = kClearX + kClearWidth; |
| constexpr GLsizei kClearY2 = kClearY + kClearHeight; |
| constexpr GLsizei kDrawX2 = kDrawX + kDrawWidth; |
| constexpr GLsizei kDrawY2 = kDrawY + kDrawHeight; |
| constexpr GLsizei kMaskedClearX2 = kMaskedClearX + kMaskedClearWidth; |
| constexpr GLsizei kMaskedClearY2 = kMaskedClearY + kMaskedClearHeight; |
| constexpr GLsizei kMaskedDrawX2 = kMaskedDrawX + kMaskedDrawWidth; |
| constexpr GLsizei kMaskedDrawY2 = kMaskedDrawY + kMaskedDrawHeight; |
| |
| constexpr GLColor kTransparentRed(255, 0, 0, 0); |
| constexpr GLColor kTransparentGreen(0, 255, 0, 0); |
| constexpr GLColor kTransparentBlue(0, 0, 255, 0); |
| constexpr GLColor kTransparentMagenta(255, 0, 255, 0); |
| |
| // Verify the black areas. |
| EXPECT_PIXEL_RECT_EQ(0, 0, kMaskedClearX, kMaskedDrawY, GLColor::black); |
| EXPECT_PIXEL_RECT_EQ(0, kMaskedDrawY2, kMaskedClearX, kSize - kMaskedDrawY2, GLColor::black); |
| EXPECT_PIXEL_RECT_EQ(kMaskedClearX2, 0, kSize - kMaskedClearX2, kDrawY, GLColor::black); |
| EXPECT_PIXEL_RECT_EQ(kMaskedClearX2, kDrawY2, kSize - kMaskedClearX2, kSize - kDrawY2, |
| GLColor::black); |
| EXPECT_PIXEL_RECT_EQ(kMaskedClearX, 0, kMaskedClearWidth, kMaskedClearY, GLColor::black); |
| EXPECT_PIXEL_RECT_EQ(kMaskedClearX2, kDrawY, kDrawX - kMaskedClearX2, kClearY - kDrawY, |
| GLColor::black); |
| EXPECT_PIXEL_RECT_EQ(kClearX2, kClearY, kDrawX - kClearX2, kMaskedDrawY - kClearY, |
| GLColor::black); |
| EXPECT_PIXEL_RECT_EQ(0, kMaskedDrawY, kMaskedDrawX, kMaskedDrawHeight, GLColor::black); |
| EXPECT_PIXEL_RECT_EQ(kMaskedClearX2, kMaskedDrawY2, kDrawX - kMaskedClearX2, |
| kSize - kMaskedDrawY2, GLColor::black); |
| |
| // Verify the red area: |
| EXPECT_PIXEL_RECT_EQ(kMaskedClearX2, kClearY, kClearX2 - kMaskedClearX2, kMaskedDrawY - kClearY, |
| GLColor::red); |
| // Verify the transparent red area: |
| EXPECT_PIXEL_RECT_EQ(kMaskedClearX2, kMaskedDrawY, kClearX2 - kMaskedClearX2, |
| kClearY2 - kMaskedDrawY, kTransparentRed); |
| // Verify the magenta area: |
| EXPECT_PIXEL_RECT_EQ(kClearX, kClearY, kMaskedClearX2 - kClearX, kMaskedDrawY - kClearY, |
| GLColor::magenta); |
| // Verify the transparent magenta area: |
| EXPECT_PIXEL_RECT_EQ(kClearX, kMaskedDrawY, kMaskedClearX2 - kClearX, kClearY2 - kMaskedDrawY, |
| kTransparentMagenta); |
| // Verify the green area: |
| EXPECT_PIXEL_RECT_EQ(kDrawX, kDrawY, kDrawWidth, kMaskedDrawY - kDrawY, GLColor::green); |
| EXPECT_PIXEL_RECT_EQ(kDrawX, kMaskedDrawY2, kDrawWidth, kDrawY2 - kMaskedDrawY2, |
| GLColor::green); |
| EXPECT_PIXEL_RECT_EQ(kMaskedDrawX2, kMaskedDrawY, kDrawX2 - kMaskedDrawX2, kMaskedDrawHeight, |
| GLColor::green); |
| // Verify the transparent green area: |
| EXPECT_PIXEL_RECT_EQ(kDrawX, kMaskedDrawY, kMaskedDrawX2 - kDrawX, kMaskedDrawHeight, |
| kTransparentGreen); |
| // Verify the blue area: |
| EXPECT_PIXEL_RECT_EQ(kMaskedClearX, kMaskedClearY, kMaskedClearWidth, kClearY - kMaskedClearY, |
| GLColor::blue); |
| EXPECT_PIXEL_RECT_EQ(kMaskedClearX, kMaskedDrawY2, kMaskedClearWidth, |
| kMaskedClearY2 - kMaskedDrawY2, GLColor::blue); |
| EXPECT_PIXEL_RECT_EQ(kMaskedClearX, kClearY, kClearX - kMaskedClearX, kMaskedDrawY - kClearY, |
| GLColor::blue); |
| // Verify the transparent blue area: |
| EXPECT_PIXEL_RECT_EQ(kMaskedClearX, kClearY2, kMaskedClearWidth, kMaskedDrawY2 - kClearY2, |
| kTransparentBlue); |
| EXPECT_PIXEL_RECT_EQ(kMaskedClearX, kMaskedDrawY, kClearX - kMaskedClearX, |
| kClearY2 - kMaskedDrawY, kTransparentBlue); |
| // Verify the transparent black area: |
| EXPECT_PIXEL_RECT_EQ(kMaskedDrawX, kMaskedDrawY, kMaskedClearX - kMaskedDrawX, |
| kMaskedDrawHeight, GLColor::transparentBlack); |
| EXPECT_PIXEL_RECT_EQ(kMaskedClearX2, kClearY2, kDrawX - kMaskedClearX2, |
| kMaskedDrawY2 - kClearY2, GLColor::transparentBlack); |
| EXPECT_PIXEL_RECT_EQ(kClearX2, kMaskedDrawY, kDrawX - kClearX2, kMaskedDrawHeight, |
| GLColor::transparentBlack); |
| } |
| |
| // Tests that changing UBO bindings does not allocate new descriptor sets. |
| TEST_P(VulkanPerformanceCounterTest, ChangingUBOsHitsDescriptorSetCache) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| // Set up two UBOs, one filled with "1" and the second with "2". |
| constexpr GLsizei kCount = 64; |
| std::vector<GLint> data1(kCount, 1); |
| std::vector<GLint> data2(kCount, 2); |
| |
| GLBuffer ubo1; |
| glBindBuffer(GL_UNIFORM_BUFFER, ubo1); |
| glBufferData(GL_UNIFORM_BUFFER, kCount * sizeof(data1[0]), data1.data(), GL_STATIC_DRAW); |
| |
| GLBuffer ubo2; |
| glBindBuffer(GL_UNIFORM_BUFFER, ubo2); |
| glBufferData(GL_UNIFORM_BUFFER, kCount * sizeof(data2[0]), data2.data(), GL_STATIC_DRAW); |
| |
| // Set up a program that verifies the contents of uniform blocks. |
| constexpr char kVS[] = R"(#version 300 es |
| precision mediump float; |
| in vec4 position; |
| void main() |
| { |
| gl_Position = position; |
| })"; |
| |
| constexpr char kFS[] = R"(#version 300 es |
| precision mediump float; |
| uniform buf { |
| int data[64/4]; |
| }; |
| uniform int checkValue; |
| out vec4 outColor; |
| |
| void main() |
| { |
| for (int i = 0; i < 64/4; ++i) { |
| if (data[i] != checkValue) { |
| outColor = vec4(1, 0, 0, 1); |
| return; |
| } |
| } |
| outColor = vec4(0, 1, 0, 1); |
| })"; |
| |
| ANGLE_GL_PROGRAM(program, kVS, kFS); |
| glUseProgram(program); |
| ASSERT_GL_NO_ERROR(); |
| |
| GLint uniLoc = glGetUniformLocation(program, "checkValue"); |
| ASSERT_NE(-1, uniLoc); |
| |
| GLuint blockIndex = glGetUniformBlockIndex(program, "buf"); |
| ASSERT_NE(blockIndex, GL_INVALID_INDEX); |
| |
| glUniformBlockBinding(program, blockIndex, 0); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Set up the rest of the GL state. |
| auto quadVerts = GetQuadVertices(); |
| GLBuffer vertexBuffer; |
| glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); |
| glBufferData(GL_ARRAY_BUFFER, quadVerts.size() * sizeof(quadVerts[0]), quadVerts.data(), |
| GL_STATIC_DRAW); |
| |
| GLint posLoc = glGetAttribLocation(program, "position"); |
| ASSERT_NE(-1, posLoc); |
| |
| glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, 0, 0); |
| glEnableVertexAttribArray(posLoc); |
| |
| // Draw a few times with each UBO. Stream out one pixel for post-render verification. |
| constexpr int kIterations = 5; |
| constexpr GLsizei kPackBufferSize = sizeof(GLColor) * kIterations * 2; |
| |
| GLBuffer packBuffer; |
| glBindBuffer(GL_PIXEL_PACK_BUFFER, packBuffer); |
| glBufferData(GL_PIXEL_PACK_BUFFER, kPackBufferSize, nullptr, GL_STREAM_READ); |
| |
| GLsizei offset = 0; |
| |
| uint32_t descriptorSetAllocationsBefore = 0; |
| |
| for (int iteration = 0; iteration < kIterations; ++iteration) |
| { |
| glUniform1i(uniLoc, 1); |
| glBindBufferBase(GL_UNIFORM_BUFFER, 0, ubo1); |
| glDrawArrays(GL_TRIANGLES, 0, 6); |
| glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, |
| reinterpret_cast<GLvoid *>(static_cast<uintptr_t>(offset))); |
| offset += sizeof(GLColor); |
| glUniform1i(uniLoc, 2); |
| glBindBufferBase(GL_UNIFORM_BUFFER, 0, ubo2); |
| glDrawArrays(GL_TRIANGLES, 0, 6); |
| glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, |
| reinterpret_cast<GLvoid *>(static_cast<uintptr_t>(offset))); |
| offset += sizeof(GLColor); |
| |
| // Capture the allocations counter after the first run. |
| if (iteration == 0) |
| { |
| descriptorSetAllocationsBefore = getPerfCounters().descriptorSetAllocations; |
| } |
| } |
| |
| EXPECT_GT(descriptorSetAllocationsBefore, 0u); |
| |
| ASSERT_GL_NO_ERROR(); |
| |
| // Verify correctness first. |
| std::vector<GLColor> expectedData(kIterations * 2, GLColor::green); |
| std::vector<GLColor> actualData(kIterations * 2, GLColor::black); |
| |
| void *mapPtr = glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, kPackBufferSize, GL_MAP_READ_BIT); |
| ASSERT_NE(nullptr, mapPtr); |
| memcpy(actualData.data(), mapPtr, kPackBufferSize); |
| |
| glUnmapBuffer(GL_PIXEL_PACK_BUFFER); |
| |
| EXPECT_EQ(expectedData, actualData); |
| |
| // Check for unnecessary descriptor set allocations. |
| uint32_t descriptorSetAllocationsAfter = getPerfCounters().descriptorSetAllocations; |
| EXPECT_EQ(descriptorSetAllocationsAfter, descriptorSetAllocationsBefore); |
| } |
| |
| // Test that mapping a buffer that the GPU is using as read-only ghosts the buffer, rather than |
| // waiting for the GPU access to complete before returning a pointer to the buffer. |
| TEST_P(VulkanPerformanceCounterTest, MappingGpuReadOnlyBufferGhostsBuffer) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| // 1. Create a buffer, map it, fill it with red |
| // 2. Draw with buffer (GPU read-only) |
| // 3. Map the same buffer and fill with white |
| // - This should ghost the buffer, rather than ending the render pass. |
| // 4. Draw with buffer |
| // 5. Update the buffer with glBufferSubData() |
| // 6. Draw with the buffer |
| // The render pass should only be broken (counters.renderPasses == 0) due to the glReadPixels() |
| // to verify the draw at the end. |
| |
| const std::array<GLColor, 4> kInitialData = {GLColor::red, GLColor::red, GLColor::red, |
| GLColor::red}; |
| const std::array<GLColor, 4> kUpdateData1 = {GLColor::white, GLColor::white, GLColor::white, |
| GLColor::white}; |
| const std::array<GLColor, 4> kUpdateData2 = {GLColor::blue, GLColor::blue, GLColor::blue, |
| GLColor::blue}; |
| |
| GLBuffer buffer; |
| glBindBuffer(GL_UNIFORM_BUFFER, buffer); |
| glBufferData(GL_UNIFORM_BUFFER, sizeof(kInitialData), kInitialData.data(), GL_DYNAMIC_DRAW); |
| glBindBufferBase(GL_UNIFORM_BUFFER, 0, buffer); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Draw |
| constexpr char kVerifyUBO[] = R"(#version 300 es |
| precision mediump float; |
| uniform block { |
| uvec4 data; |
| } ubo; |
| uniform uint expect; |
| uniform vec4 successOutput; |
| out vec4 colorOut; |
| void main() |
| { |
| if (all(equal(ubo.data, uvec4(expect)))) |
| colorOut = successOutput; |
| else |
| colorOut = vec4(1.0, 0, 0, 1.0); |
| })"; |
| |
| ANGLE_GL_PROGRAM(verifyUbo, essl3_shaders::vs::Simple(), kVerifyUBO); |
| glUseProgram(verifyUbo); |
| |
| GLint expectLoc = glGetUniformLocation(verifyUbo, "expect"); |
| ASSERT_NE(-1, expectLoc); |
| GLint successLoc = glGetUniformLocation(verifyUbo, "successOutput"); |
| ASSERT_NE(-1, successLoc); |
| |
| glUniform1ui(expectLoc, kInitialData[0].asUint()); |
| glUniform4f(successLoc, 0, 1, 0, 1); |
| |
| drawQuad(verifyUbo, essl3_shaders::PositionAttrib(), 0.5); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Map the buffer and update it. |
| // This should ghost the buffer and avoid breaking the render pass, since the GPU is only |
| // reading it. |
| void *mappedBuffer = |
| glMapBufferRange(GL_UNIFORM_BUFFER, 0, sizeof(kInitialData), GL_MAP_WRITE_BIT); |
| // 'renderPasses == 0' here means the render pass was broken and a new one was started. |
| ASSERT_EQ(getPerfCounters().renderPasses, 1u); |
| ASSERT_EQ(getPerfCounters().buffersGhosted, 1u); |
| |
| memcpy(mappedBuffer, kUpdateData1.data(), sizeof(kInitialData)); |
| |
| glUnmapBuffer(GL_UNIFORM_BUFFER); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Verify that the buffer has the updated value. |
| glUniform1ui(expectLoc, kUpdateData1[0].asUint()); |
| glUniform4f(successLoc, 0, 0, 1, 1); |
| |
| drawQuad(verifyUbo, essl3_shaders::PositionAttrib(), 0.5); |
| ASSERT_GL_NO_ERROR(); |
| ASSERT_EQ(getPerfCounters().renderPasses, 1u); |
| |
| // Update the buffer with glBufferSubData |
| glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(kUpdateData2), kUpdateData2.data()); |
| ASSERT_GL_NO_ERROR(); |
| ASSERT_EQ(getPerfCounters().renderPasses, 1u); |
| |
| // Verify that the buffer has the updated value. |
| glUniform1ui(expectLoc, kUpdateData2[0].asUint()); |
| glUniform4f(successLoc, 0, 1, 1, 1); |
| |
| drawQuad(verifyUbo, essl3_shaders::PositionAttrib(), 0.5); |
| ASSERT_GL_NO_ERROR(); |
| ASSERT_EQ(getPerfCounters().renderPasses, 1u); |
| |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::cyan); |
| } |
| |
| // Verifies that BufferSubData calls don't trigger state updates for non-translated formats. |
| TEST_P(VulkanPerformanceCounterTest, BufferSubDataShouldNotTriggerSyncState) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green()); |
| glUseProgram(testProgram); |
| |
| GLint posLoc = glGetAttribLocation(testProgram, essl1_shaders::PositionAttrib()); |
| ASSERT_NE(-1, posLoc); |
| |
| setupQuadVertexBuffer(0.5f, 1.0f); |
| glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr); |
| glEnableVertexAttribArray(posLoc); |
| |
| glDrawArrays(GL_TRIANGLES, 0, 6); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| |
| EXPECT_EQ(getPerfCounters().vertexArraySyncStateCalls, 1u); |
| |
| const std::array<Vector3, 6> &quadVertices = GetQuadVertices(); |
| size_t bufferSize = sizeof(quadVertices[0]) * quadVertices.size(); |
| |
| glBufferSubData(GL_ARRAY_BUFFER, 0, bufferSize, quadVertices.data()); |
| |
| glDrawArrays(GL_TRIANGLES, 0, 6); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| |
| EXPECT_EQ(getPerfCounters().vertexArraySyncStateCalls, 1u); |
| |
| // Verify the BufferData with a whole buffer size is treated like the SubData call. |
| glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices[0]) * quadVertices.size(), |
| quadVertices.data(), GL_STATIC_DRAW); |
| glDrawArrays(GL_TRIANGLES, 0, 6); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| |
| EXPECT_EQ(getPerfCounters().vertexArraySyncStateCalls, 1u); |
| } |
| |
| // Verifies that rendering to backbuffer discards depth/stencil. |
| TEST_P(VulkanPerformanceCounterTest, SwapShouldInvalidateDepthStencil) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| angle::VulkanPerfCounters expected; |
| |
| // Expect rpCount+1, depth(Clears+1, Loads+0, LoadNones+0, Stores+0, StoreNones+0), |
| // stencil(Clears+1, Loads+0, LoadNones+0, Stores+0, StoreNones+0) |
| setExpectedCountersForDepthOps(getPerfCounters(), 1, 1, 0, 0, 0, 0, &expected); |
| setExpectedCountersForStencilOps(getPerfCounters(), 1, 0, 0, 0, 0, &expected); |
| |
| // Clear to verify that _some_ counters did change (as opposed to for example all being reset on |
| // swap) |
| glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| glEnable(GL_DEPTH_TEST); |
| glDepthMask(GL_TRUE); |
| glDepthFunc(GL_ALWAYS); |
| glEnable(GL_STENCIL_TEST); |
| glStencilFunc(GL_ALWAYS, 0x00, 0xFF); |
| glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); |
| |
| ANGLE_GL_PROGRAM(drawGreen, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green()); |
| drawQuad(drawGreen, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Swap buffers to implicitely resolve |
| swapBuffers(); |
| compareDepthStencilOpCounters(getPerfCounters(), expected); |
| } |
| |
| // Verifies that rendering to MSAA backbuffer discards depth/stencil. |
| TEST_P(VulkanPerformanceCounterTest_MSAA, SwapShouldInvalidateDepthStencil) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| angle::VulkanPerfCounters expected; |
| |
| // Expect rpCount+1, depth(Clears+1, Loads+0, LoadNones+0, Stores+0, StoreNones+0), |
| // stencil(Clears+1, Loads+0, LoadNones+0, Stores+0, StoreNones+0) |
| setExpectedCountersForDepthOps(getPerfCounters(), 1, 1, 0, 0, 0, 0, &expected); |
| setExpectedCountersForStencilOps(getPerfCounters(), 1, 0, 0, 0, 0, &expected); |
| |
| // Clear to verify that _some_ counters did change (as opposed to for example all being reset on |
| // swap) |
| glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| glEnable(GL_DEPTH_TEST); |
| glDepthMask(GL_TRUE); |
| glDepthFunc(GL_ALWAYS); |
| glEnable(GL_STENCIL_TEST); |
| glStencilFunc(GL_ALWAYS, 0x00, 0xFF); |
| glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); |
| |
| ANGLE_GL_PROGRAM(drawGreen, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green()); |
| drawQuad(drawGreen, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Swap buffers to implicitely resolve |
| swapBuffers(); |
| compareDepthStencilOpCounters(getPerfCounters(), expected); |
| } |
| |
| // Verifies that multisample swapchain resolve occurs in subpass. |
| TEST_P(VulkanPerformanceCounterTest_MSAA, SwapShouldResolveWithSubpass) |
| { |
| angle::VulkanPerfCounters expected; |
| // Expect rpCount+1, color(Clears+1, Loads+0, LoadNones+0, Stores+1, StoreNones+0) |
| setExpectedCountersForColorOps(getPerfCounters(), 1, 1, 0, 0, 1, 0, &expected); |
| |
| uint32_t expectedResolvesSubpass = getPerfCounters().swapchainResolveInSubpass + 1; |
| uint32_t expectedResolvesOutside = getPerfCounters().swapchainResolveOutsideSubpass; |
| |
| // Clear color. |
| glClearColor(0.0f, 0.0f, 0.0f, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
| |
| // Set up program |
| ANGLE_GL_PROGRAM(drawColor, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor()); |
| glUseProgram(drawColor); |
| GLint colorUniformLocation = |
| glGetUniformLocation(drawColor, angle::essl1_shaders::ColorUniform()); |
| ASSERT_NE(colorUniformLocation, -1); |
| |
| // Draw green |
| glUniform4f(colorUniformLocation, 0.0f, 1.0f, 0.0f, 1.0f); |
| drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.95f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Swap buffers to implicitly resolve |
| swapBuffers(); |
| EXPECT_EQ(getPerfCounters().swapchainResolveInSubpass, expectedResolvesSubpass); |
| EXPECT_EQ(getPerfCounters().swapchainResolveOutsideSubpass, expectedResolvesOutside); |
| |
| compareColorOpCounters(getPerfCounters(), expected); |
| } |
| |
| // Verifies that in a multisample swapchain, drawing to the default FBO followed by user FBO and |
| // then swapping triggers the resolve outside the optimization subpass. |
| TEST_P(VulkanPerformanceCounterTest_MSAA, SwapAfterDrawToDifferentFBOsShouldResolveOutsideSubpass) |
| { |
| constexpr GLsizei kSize = 16; |
| angle::VulkanPerfCounters expected; |
| // Expect rpCount+1, color(Clears+1, Loads+0, LoadNones+0, Stores+2, StoreNones+0) |
| setExpectedCountersForColorOps(getPerfCounters(), 1, 1, 0, 0, 2, 0, &expected); |
| |
| uint32_t expectedResolvesSubpass = getPerfCounters().swapchainResolveInSubpass; |
| uint32_t expectedResolvesOutside = getPerfCounters().swapchainResolveOutsideSubpass + 1; |
| |
| // Create a framebuffer to clear. |
| GLTexture color; |
| glBindTexture(GL_TEXTURE_2D, color); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color, 0); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Clear color. |
| glClearColor(0.0f, 0.0f, 0.0f, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
| |
| // Set up program |
| ANGLE_GL_PROGRAM(drawColor, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor()); |
| glUseProgram(drawColor); |
| GLint colorUniformLocation = |
| glGetUniformLocation(drawColor, angle::essl1_shaders::ColorUniform()); |
| ASSERT_NE(colorUniformLocation, -1); |
| |
| // Draw green to default framebuffer |
| glBindFramebuffer(GL_FRAMEBUFFER, 0); |
| glUniform4f(colorUniformLocation, 0.0f, 1.0f, 0.0f, 1.0f); |
| drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.95f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Draw blue to the user framebuffer |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| glUniform4f(colorUniformLocation, 0.0f, 0.0f, 1.0f, 1.0f); |
| drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.95f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Swap buffers to resolve outside the optimization subpass |
| swapBuffers(); |
| EXPECT_EQ(getPerfCounters().swapchainResolveInSubpass, expectedResolvesSubpass); |
| EXPECT_EQ(getPerfCounters().swapchainResolveOutsideSubpass, expectedResolvesOutside); |
| |
| compareColorOpCounters(getPerfCounters(), expected); |
| } |
| |
| // Tests that uniform updates eventually stop updating descriptor sets. |
| TEST_P(VulkanPerformanceCounterTest, UniformUpdatesHitDescriptorSetCache) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor()); |
| glUseProgram(testProgram); |
| GLint posLoc = glGetAttribLocation(testProgram, essl1_shaders::PositionAttrib()); |
| GLint uniLoc = glGetUniformLocation(testProgram, essl1_shaders::ColorUniform()); |
| |
| std::array<Vector3, 6> quadVerts = GetQuadVertices(); |
| |
| GLBuffer vbo; |
| glBindBuffer(GL_ARRAY_BUFFER, vbo); |
| glBufferData(GL_ARRAY_BUFFER, quadVerts.size() * sizeof(quadVerts[0]), quadVerts.data(), |
| GL_STATIC_DRAW); |
| |
| glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr); |
| glEnableVertexAttribArray(posLoc); |
| |
| ASSERT_GL_NO_ERROR(); |
| |
| // Choose a number of iterations sufficiently large to ensure all uniforms are cached. |
| constexpr int kIterations = 2000; |
| |
| RNG rng; |
| |
| // First pass: cache all the uniforms. |
| for (int iteration = 0; iteration < kIterations; ++iteration) |
| { |
| Vector3 randomVec3 = RandomVec3(rng.randomInt(), 0.0f, 1.0f); |
| |
| glUniform4f(uniLoc, randomVec3.x(), randomVec3.y(), randomVec3.z(), 1.0f); |
| glDrawArrays(GL_TRIANGLES, 0, 6); |
| |
| GLColor expectedColor = GLColor(randomVec3); |
| EXPECT_PIXEL_COLOR_NEAR(0, 0, expectedColor, 5); |
| } |
| |
| ASSERT_GL_NO_ERROR(); |
| |
| uint32_t expectedCacheMisses = getPerfCounters().uniformsAndXfbDescriptorSetCacheMisses; |
| EXPECT_GT(expectedCacheMisses, 0u); |
| |
| // Second pass: ensure all the uniforms are cached. |
| for (int iteration = 0; iteration < kIterations; ++iteration) |
| { |
| Vector3 randomVec3 = RandomVec3(rng.randomInt(), 0.0f, 1.0f); |
| |
| glUniform4f(uniLoc, randomVec3.x(), randomVec3.y(), randomVec3.z(), 1.0f); |
| glDrawArrays(GL_TRIANGLES, 0, 6); |
| |
| GLColor expectedColor = GLColor(randomVec3); |
| EXPECT_PIXEL_COLOR_NEAR(0, 0, expectedColor, 5); |
| } |
| |
| ASSERT_GL_NO_ERROR(); |
| |
| uint32_t actualCacheMisses = getPerfCounters().uniformsAndXfbDescriptorSetCacheMisses; |
| EXPECT_EQ(expectedCacheMisses, actualCacheMisses); |
| } |
| |
| // Verify a mid-render pass clear of a newly enabled attachment uses LOAD_OP_CLEAR. |
| TEST_P(VulkanPerformanceCounterTest, DisableThenMidRenderPassClear) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| // This optimization is not implemented when this workaround is in effect. |
| ANGLE_SKIP_TEST_IF(mPreferDrawOverClearAttachments == ANGLEFeature::Supported); |
| |
| angle::VulkanPerfCounters expected; |
| |
| // Expect rpCount+1, color(Clears+1, Loads+0, LoadNones+0, Stores+2, StoreNones+0) |
| // vkCmdClearAttachments should be used for color attachment 0. |
| setExpectedCountersForColorOps(getPerfCounters(), 1, 1, 0, 0, 2, 0, &expected); |
| expected.colorClearAttachments = getPerfCounters().colorClearAttachments + 1; |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| |
| GLTexture textures[2]; |
| |
| glBindTexture(GL_TEXTURE_2D, textures[0]); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0], 0); |
| |
| glBindTexture(GL_TEXTURE_2D, textures[1]); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, textures[1], 0); |
| |
| // Only enable attachment 0. |
| GLenum drawBuffers[] = {GL_COLOR_ATTACHMENT0, GL_NONE}; |
| glDrawBuffers(2, drawBuffers); |
| |
| // Draw red. |
| ANGLE_GL_PROGRAM(redProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); |
| drawQuad(redProgram, essl1_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Enable attachment 1. |
| drawBuffers[1] = GL_COLOR_ATTACHMENT1; |
| glDrawBuffers(2, drawBuffers); |
| |
| // Clear both attachments to green. |
| glClearColor(0.0f, 1.0f, 0.0f, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| constexpr char kFS[] = R"(#version 300 es |
| precision highp float; |
| layout(location = 0) out vec4 my_FragColor0; |
| layout(location = 1) out vec4 my_FragColor1; |
| void main() |
| { |
| my_FragColor0 = vec4(0.0, 0.0, 1.0, 1.0); |
| my_FragColor1 = vec4(0.0, 0.0, 1.0, 1.0); |
| })"; |
| |
| // Draw blue to both attachments. |
| ANGLE_GL_PROGRAM(blueProgram, essl3_shaders::vs::Simple(), kFS); |
| drawQuad(blueProgram, essl3_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| |
| EXPECT_EQ(expected.renderPasses, getPerfCounters().renderPasses); |
| |
| // Verify attachment 0. |
| glReadBuffer(GL_COLOR_ATTACHMENT0); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_EQ(0, 0, 0, 0, 255, 255); |
| // Verify attachment 1. |
| glReadBuffer(GL_COLOR_ATTACHMENT1); |
| ASSERT_GL_NO_ERROR(); |
| EXPECT_PIXEL_EQ(0, 0, 0, 0, 255, 255); |
| |
| compareColorOpCounters(getPerfCounters(), expected); |
| compareClearAttachmentsCounter(expected.colorClearAttachments, |
| getPerfCounters().colorClearAttachments); |
| |
| // Expect rpCount+1, color(Clears+0, Loads+1, LoadNones+0, Stores+1, StoreNones+0) |
| setExpectedCountersForColorOps(getPerfCounters(), 1, 0, 1, 0, 1, 0, &expected); |
| |
| GLFramebuffer fbo2; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo2); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[1], 0); |
| |
| glEnable(GL_BLEND); |
| glBlendFunc(GL_ONE, GL_ONE); |
| |
| // Blend red |
| drawQuad(redProgram, essl3_shaders::PositionAttrib(), 0.5f); |
| ASSERT_GL_NO_ERROR(); |
| |
| EXPECT_EQ(expected.renderPasses, getPerfCounters().renderPasses); |
| |
| // Verify purple |
| glReadBuffer(GL_COLOR_ATTACHMENT0); |
| EXPECT_PIXEL_EQ(0, 0, 255, 0, 255, 255); |
| ASSERT_GL_NO_ERROR(); |
| |
| compareColorOpCounters(getPerfCounters(), expected); |
| } |
| |
| // Copy of ClearTest.InceptionScissorClears. |
| // Clears many small concentric rectangles using scissor regions. Verifies vkCmdClearAttachments() |
| // is used for the scissored clears, rather than vkCmdDraw(). |
| TEST_P(VulkanPerformanceCounterTest, InceptionScissorClears) |
| { |
| // https://issuetracker.google.com/166809097 |
| ANGLE_SKIP_TEST_IF(IsQualcomm() && IsVulkan()); |
| |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| angle::VulkanPerfCounters expected; |
| |
| // Expect rpCount+1, color(Clears+1, Loads+0, LoadNones+0, Stores+1, StoreNones+0) |
| setExpectedCountersForColorOps(getPerfCounters(), 1, 1, 0, 0, 1, 0, &expected); |
| |
| angle::RNG rng; |
| |
| constexpr GLuint kSize = 16; |
| |
| // Create a square user FBO so we have more control over the dimensions. |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| |
| GLRenderbuffer rbo; |
| glBindRenderbuffer(GL_RENDERBUFFER, rbo); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, kSize, kSize); |
| |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| glViewport(0, 0, kSize, kSize); |
| |
| // Clear small concentric squares using scissor. |
| std::vector<GLColor> expectedColors; |
| // TODO(syoussefi): verify this |
| ANGLE_MAYBE_UNUSED uint32_t numScissoredClears = 0; |
| for (GLuint index = 0; index < (kSize - 1) / 2; index++) |
| { |
| // Do the first clear without the scissor. |
| if (index > 0) |
| { |
| glEnable(GL_SCISSOR_TEST); |
| glScissor(index, index, kSize - (index * 2), kSize - (index * 2)); |
| ++numScissoredClears; |
| } |
| |
| GLColor color = RandomColor(&rng); |
| expectedColors.push_back(color); |
| Vector4 floatColor = color.toNormalizedVector(); |
| glClearColor(floatColor[0], floatColor[1], floatColor[2], floatColor[3]); |
| glClear(GL_COLOR_BUFFER_BIT); |
| } |
| |
| ASSERT_GL_NO_ERROR(); |
| |
| // Make sure everything was done in a single renderpass. |
| EXPECT_EQ(expected.renderPasses, getPerfCounters().renderPasses); |
| |
| std::vector<GLColor> actualColors(expectedColors.size()); |
| glReadPixels(0, kSize / 2, actualColors.size(), 1, GL_RGBA, GL_UNSIGNED_BYTE, |
| actualColors.data()); |
| |
| EXPECT_EQ(expectedColors, actualColors); |
| |
| compareColorOpCounters(getPerfCounters(), expected); |
| } |
| |
| // Copy of ClearTest.Depth16Scissored. |
| // Clears many small concentric rectangles using scissor regions. Verifies vkCmdClearAttachments() |
| // is used for the scissored clears, rather than vkCmdDraw(). |
| TEST_P(VulkanPerformanceCounterTest, Depth16Scissored) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| GLRenderbuffer renderbuffer; |
| glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer); |
| constexpr int kRenderbufferSize = 64; |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, kRenderbufferSize, |
| kRenderbufferSize); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderbuffer); |
| |
| glClearDepthf(0.0f); |
| glClear(GL_DEPTH_BUFFER_BIT); |
| |
| glEnable(GL_SCISSOR_TEST); |
| constexpr int kNumSteps = 13; |
| // TODO(syoussefi): verify this |
| ANGLE_MAYBE_UNUSED uint32_t numScissoredClears = 0; |
| for (int ndx = 1; ndx < kNumSteps; ndx++) |
| { |
| float perc = static_cast<float>(ndx) / static_cast<float>(kNumSteps); |
| glScissor(0, 0, static_cast<int>(kRenderbufferSize * perc), |
| static_cast<int>(kRenderbufferSize * perc)); |
| glClearDepthf(perc); |
| glClear(GL_DEPTH_BUFFER_BIT); |
| ++numScissoredClears; |
| } |
| |
| // Make sure everything was done in a single renderpass. |
| EXPECT_EQ(getPerfCounters().renderPasses, 1u); |
| } |
| |
| // Copy of ClearTest.InceptionScissorClears. |
| // Clears many small concentric rectangles using scissor regions. |
| TEST_P(VulkanPerformanceCounterTest, DrawThenInceptionScissorClears) |
| { |
| // https://issuetracker.google.com/166809097 |
| ANGLE_SKIP_TEST_IF(IsQualcomm() && IsVulkan()); |
| |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| angle::VulkanPerfCounters expected; |
| |
| // Expect rpCount+1, color(Clears+0, Loads+0, LoadNones+0, Stores+1, StoreNones+0) |
| setExpectedCountersForColorOps(getPerfCounters(), 1, 0, 0, 0, 1, 0, &expected); |
| |
| angle::RNG rng; |
| std::vector<GLColor> expectedColors; |
| constexpr GLuint kSize = 16; |
| |
| // Create a square user FBO so we have more control over the dimensions. |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| |
| GLRenderbuffer rbo; |
| glBindRenderbuffer(GL_RENDERBUFFER, rbo); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, kSize, kSize); |
| |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| glViewport(0, 0, kSize, kSize); |
| |
| ANGLE_GL_PROGRAM(redProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); |
| drawQuad(redProgram, essl1_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| expectedColors.push_back(GLColor::red); |
| |
| compareColorOpCounters(getPerfCounters(), expected); |
| |
| // Expect rpCount+1, color(Clears+0, Loads+1, LoadNones+0, Stores+1, StoreNones+0) |
| // TODO: Optimize scissored clears to use loadOp = CLEAR. anglebug.com/5194 |
| setExpectedCountersForColorOps(getPerfCounters(), 1, 0, 1, 0, 1, 0, &expected); |
| |
| // Draw small concentric squares using scissor. |
| // TODO(syoussefi): verify this |
| ANGLE_MAYBE_UNUSED uint32_t numScissoredClears = 0; |
| // All clears are to a scissored render area. |
| for (GLuint index = 1; index < (kSize - 1) / 2; index++) |
| { |
| glEnable(GL_SCISSOR_TEST); |
| glScissor(index, index, kSize - (index * 2), kSize - (index * 2)); |
| ++numScissoredClears; |
| |
| GLColor color = RandomColor(&rng); |
| expectedColors.push_back(color); |
| Vector4 floatColor = color.toNormalizedVector(); |
| glClearColor(floatColor[0], floatColor[1], floatColor[2], floatColor[3]); |
| glClear(GL_COLOR_BUFFER_BIT); |
| } |
| |
| ASSERT_GL_NO_ERROR(); |
| |
| // Make sure everything was done in a single renderpass. |
| EXPECT_EQ(expected.renderPasses, getPerfCounters().renderPasses); |
| |
| // Close the render pass to update the performance counters. |
| std::vector<GLColor> actualColors(expectedColors.size()); |
| glReadPixels(0, kSize / 2, actualColors.size(), 1, GL_RGBA, GL_UNSIGNED_BYTE, |
| actualColors.data()); |
| EXPECT_EQ(expectedColors, actualColors); |
| |
| compareColorOpCounters(getPerfCounters(), expected); |
| } |
| |
| // Test that color clears are respected after invalidate |
| TEST_P(VulkanPerformanceCounterTest, ColorClearAfterInvalidate) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| angle::VulkanPerfCounters expected; |
| |
| GLFramebuffer framebuffer; |
| GLTexture texture; |
| GLRenderbuffer renderbuffer; |
| setupForColorDepthOpsTest(&framebuffer, &texture, &renderbuffer); |
| |
| // Execute the scenario that this test is for: |
| |
| // color+depth invalidate, color+depth clear |
| // |
| // Expected: |
| // rpCount+1, |
| // depth(Clears+1, Loads+0, LoadNones+0, Stores+0, StoreNones+0) |
| // color(Clears+1, Loads+0, LoadNones+0, Stores+1, StoreNones+0) |
| setExpectedCountersForDepthOps(getPerfCounters(), 0, 1, 0, 0, 0, 0, &expected); |
| setExpectedCountersForColorOps(getPerfCounters(), 1, 1, 0, 0, 1, 0, &expected); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); |
| |
| // Invalidate (loadOp C=DONTCARE, D=DONTCARE) |
| const GLenum discards[] = {GL_DEPTH_ATTACHMENT, GL_COLOR_ATTACHMENT0}; |
| glInvalidateFramebuffer(GL_FRAMEBUFFER, 2, discards); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Clear (loadOp C=CLEAR, D=CLEAR) |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
| |
| // Save existing draw buffers |
| GLint maxDrawBuffers = 0; |
| glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers); |
| std::vector<GLenum> savedDrawBuffers(maxDrawBuffers); |
| for (int i = 0; i < maxDrawBuffers; i++) |
| glGetIntegerv(GL_DRAW_BUFFER0 + i, (GLint *)&savedDrawBuffers[i]); |
| |
| // Draw depth-only |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); |
| glDrawBuffers(0, nullptr); |
| glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| glDrawBuffers(maxDrawBuffers, savedDrawBuffers.data()); |
| glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Invalidate depth only (storeOp should be C=STORE/D=CLEAR) |
| glInvalidateFramebuffer(GL_FRAMEBUFFER, 1, discards); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, 0); |
| |
| EXPECT_EQ(expected.renderPasses, getPerfCounters().renderPasses); |
| |
| // Use swapBuffers and then check how many loads and stores were actually done |
| swapBuffers(); |
| compareColorOpCounters(getPerfCounters(), expected); |
| compareDepthOpCounters(getPerfCounters(), expected); |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| // Ensure that image gets marked as defined after clear + invalidate + clear, and that we use |
| // LoadOp=Load for a renderpass which draws to it after the clear has been flushed with a blit. |
| TEST_P(VulkanPerformanceCounterTest, InvalidateThenRepeatedClearThenBlitThenDraw) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| angle::VulkanPerfCounters expected; |
| |
| constexpr GLsizei kSize = 2; |
| |
| // tex[0] is what's being tested. The others are helpers. |
| GLTexture tex[3]; |
| for (int i = 0; i < 3; ++i) |
| { |
| glBindTexture(GL_TEXTURE_2D, tex[i]); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| nullptr); |
| } |
| |
| GLFramebuffer fbo[3]; |
| for (int i = 0; i < 3; ++i) |
| { |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo[i]); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex[i], 0); |
| } |
| |
| // Expect rpCount+1, color(Clears+0, Loads+1, LoadNones+0, Stores+1, StoreNones+0) |
| setExpectedCountersForColorOps(getPerfCounters(), 1, 0, 1, 0, 1, 0, &expected); |
| |
| // Clear the image through fbo[0], and make sure the clear is flushed outside the render pass. |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo[0]); |
| glClearColor(1, 0, 0, 1); |
| glClear(GL_COLOR_BUFFER_BIT); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| |
| // Invalidate it such that the contents are marked as undefined. Note that regardless of the |
| // marking, the image is cleared nevertheless. |
| const GLenum discards[] = {GL_COLOR_ATTACHMENT0}; |
| glInvalidateFramebuffer(GL_FRAMEBUFFER, 1, discards); |
| |
| // Clear it again to the same color. |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| // Bind tex[0] to fbo[1] as the read fbo, and blit to fbo[2] |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo[1]); |
| glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex[0], 0); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo[2]); |
| |
| // Blit. This causes the second clear of tex[0] to be flushed outside the render pass, which |
| // may be optimized out. |
| glBlitFramebuffer(0, 0, kSize, kSize, 0, 0, kSize, kSize, GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| |
| // Switch back to fbo[0] and draw with blend. If the second clear is dropped and the image |
| // continues to be marked as invalidated, loadOp=DONT_CARE would be used instead of loadOp=LOAD. |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo[0]); |
| |
| glEnable(GL_BLEND); |
| glBlendFunc(GL_ONE, GL_ONE); |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Blue()); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0); |
| |
| EXPECT_EQ(expected.renderPasses, getPerfCounters().renderPasses); |
| |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::magenta); |
| compareColorOpCounters(getPerfCounters(), expected); |
| } |
| |
| // Ensure that image gets marked as defined after clear + invalidate + clear, and that we use |
| // LoadOp=Load for a renderpass which draws to it after the clear has been flushed with read pixels. |
| TEST_P(VulkanPerformanceCounterTest, InvalidateThenRepeatedClearThenReadbackThenDraw) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| angle::VulkanPerfCounters expected; |
| |
| constexpr GLsizei kSize = 2; |
| |
| GLTexture tex; |
| glBindTexture(GL_TEXTURE_2D, tex); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0); |
| |
| // Expect rpCount+1, color(Clears+0, Loads+1, LoadNones+0, Stores+1, StoreNones+0) |
| setExpectedCountersForColorOps(getPerfCounters(), 1, 0, 1, 0, 1, 0, &expected); |
| |
| // Clear the image, and make sure the clear is flushed outside the render pass. |
| glClearColor(1, 0, 0, 1); |
| glClear(GL_COLOR_BUFFER_BIT); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| |
| // Invalidate it such that the contents are marked as undefined. Note that regarldess of the |
| // marking, the image is cleared nevertheless. |
| const GLenum discards[] = {GL_COLOR_ATTACHMENT0}; |
| glInvalidateFramebuffer(GL_FRAMEBUFFER, 1, discards); |
| |
| // Clear it again to the same color, and make sure the clear is flushed outside the render pass, |
| // which may be optimized out. |
| glClear(GL_COLOR_BUFFER_BIT); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| |
| // Draw with blend. If the second clear is dropped and the image continues to be marked as |
| // invalidated, loadOp=DONT_CARE would be used instead of loadOp=LOAD. |
| glEnable(GL_BLEND); |
| glBlendFunc(GL_ONE, GL_ONE); |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Blue()); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0); |
| |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::magenta); |
| compareColorOpCounters(getPerfCounters(), expected); |
| } |
| |
| // Tests that the submission counters count the implicit submission in eglSwapBuffers(). |
| TEST_P(VulkanPerformanceCounterTest, VerifySubmitCounters) |
| { |
| initANGLEFeatures(); |
| |
| uint32_t expectedVkQueueSubmitCount = getPerfCounters().vkQueueSubmitCallsTotal; |
| uint32_t expectedCommandQueueSubmitCount = getPerfCounters().commandQueueSubmitCallsTotal; |
| |
| // One submission coming from clear and read back |
| ++expectedVkQueueSubmitCount; |
| ++expectedCommandQueueSubmitCount; |
| |
| glClearColor(1, 0, 0, 1); |
| glClear(GL_COLOR_BUFFER_BIT); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| |
| EXPECT_EQ(getPerfCounters().vkQueueSubmitCallsTotal, expectedVkQueueSubmitCount); |
| EXPECT_EQ(getPerfCounters().commandQueueSubmitCallsTotal, expectedCommandQueueSubmitCount); |
| |
| // One submission coming from draw and implicit submission from eglSwapBuffers |
| ++expectedVkQueueSubmitCount; |
| ++expectedCommandQueueSubmitCount; |
| |
| ANGLE_GL_PROGRAM(drawGreen, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green()); |
| drawQuad(drawGreen, essl1_shaders::PositionAttrib(), 1.f); |
| swapBuffers(); |
| |
| EXPECT_EQ(getPerfCounters().vkQueueSubmitCallsTotal, expectedVkQueueSubmitCount); |
| EXPECT_EQ(getPerfCounters().commandQueueSubmitCallsTotal, expectedCommandQueueSubmitCount); |
| } |
| |
| // Ensure that glFlush doesn't lead to vkQueueSubmit if there's nothing to submit. |
| TEST_P(VulkanPerformanceCounterTest, UnnecessaryFlushDoesntCauseSubmission) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| swapBuffers(); |
| uint32_t expectedVkQueueSubmitCalls = getPerfCounters().vkQueueSubmitCallsTotal; |
| |
| glFlush(); |
| glFlush(); |
| glFlush(); |
| |
| // Nothing was recorded, so there shouldn't be anything to flush. |
| glFinish(); |
| EXPECT_EQ(getPerfCounters().vkQueueSubmitCallsTotal, expectedVkQueueSubmitCalls); |
| |
| glClearColor(1, 0, 0, 1); |
| glClear(GL_COLOR_BUFFER_BIT); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| |
| // One submission for the above readback |
| ++expectedVkQueueSubmitCalls; |
| |
| glFinish(); |
| EXPECT_EQ(getPerfCounters().vkQueueSubmitCallsTotal, expectedVkQueueSubmitCalls); |
| |
| glFlush(); |
| glFlush(); |
| glFlush(); |
| |
| // No addional submissions since last one |
| glFinish(); |
| EXPECT_EQ(getPerfCounters().vkQueueSubmitCallsTotal, expectedVkQueueSubmitCalls); |
| } |
| |
| // Ensure that glFenceSync doesn't lead to vkQueueSubmit if there's nothing to submit. |
| TEST_P(VulkanPerformanceCounterTest, SyncWihtoutCommandsDoesntCauseSubmission) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| swapBuffers(); |
| uint32_t expectedVkQueueSubmitCalls = getPerfCounters().vkQueueSubmitCallsTotal; |
| |
| glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); |
| |
| // Nothing was recorded, so there shouldn't be anything to flush. |
| glFinish(); |
| EXPECT_EQ(getPerfCounters().vkQueueSubmitCallsTotal, expectedVkQueueSubmitCalls); |
| } |
| |
| // In single-buffer mode, ensure that unnecessary eglSwapBuffers is completely ignored (i.e. doesn't |
| // lead to a command queue submission, consuming a submission serial). Used to verify an |
| // optimization that ensures CPU throttling doesn't incur GPU bubbles with unnecessary |
| // eglSwapBuffers calls. |
| TEST_P(VulkanPerformanceCounterTest_SingleBuffer, SwapBuffersAfterFlushIgnored) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName)); |
| initANGLEFeatures(); |
| |
| // Set mode to single buffer |
| EXPECT_EGL_TRUE(eglSurfaceAttrib(getEGLWindow()->getDisplay(), getEGLWindow()->getSurface(), |
| EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER)); |
| |
| // Swap buffers so mode switch takes effect. |
| swapBuffers(); |
| uint32_t expectedCommandQueueSubmitCalls = getPerfCounters().commandQueueSubmitCallsTotal; |
| |
| // Further swap buffers should be ineffective. |
| swapBuffers(); |
| swapBuffers(); |
| swapBuffers(); |
| swapBuffers(); |
| |
| EXPECT_EQ(getPerfCounters().commandQueueSubmitCallsTotal, expectedCommandQueueSubmitCalls); |
| |
| // Issue commands and flush them. |
| glClearColor(1, 0, 0, 1); |
| glClear(GL_COLOR_BUFFER_BIT); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| |
| // One submission for the above readback |
| ++expectedCommandQueueSubmitCalls; |
| EXPECT_EQ(getPerfCounters().commandQueueSubmitCallsTotal, expectedCommandQueueSubmitCalls); |
| |
| // Further swap buffers should again be ineffective. |
| swapBuffers(); |
| swapBuffers(); |
| swapBuffers(); |
| swapBuffers(); |
| swapBuffers(); |
| |
| EXPECT_EQ(getPerfCounters().commandQueueSubmitCallsTotal, expectedCommandQueueSubmitCalls); |
| } |
| |
| ANGLE_INSTANTIATE_TEST(VulkanPerformanceCounterTest, ES3_VULKAN(), ES3_VULKAN_SWIFTSHADER()); |
| ANGLE_INSTANTIATE_TEST(VulkanPerformanceCounterTest_ES31, ES31_VULKAN(), ES31_VULKAN_SWIFTSHADER()); |
| ANGLE_INSTANTIATE_TEST(VulkanPerformanceCounterTest_MSAA, ES3_VULKAN(), ES3_VULKAN_SWIFTSHADER()); |
| |
| GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VulkanPerformanceCounterTest_SingleBuffer); |
| ANGLE_INSTANTIATE_TEST(VulkanPerformanceCounterTest_SingleBuffer, ES3_VULKAN()); |
| |
| } // anonymous namespace |