Reland "Vulkan: Accelerate Texture PBO updates"
This reverts commit 27d3c9399925d23726880ef910b9068fa39307cf.
Reason for revert: Investigation is unable to reproduce the regresion.
Shows up on the perf CI.
Original change's description:
> Revert "Vulkan: Accelerate Texture PBO updates"
>
> This reverts commit efb45edaefc07fc7120ebbde83bbc84876afda1a.
>
> Reason for revert: Significant perf regression on several benchmarks.
> See bug for more details.
>
> Bug: chromium:1027098
>
> Original change's description:
> > Vulkan: Accelerate Texture PBO updates
> >
> > If the format of the image and the PBO match,
> > use a vkCmdCopyBufferToImage transfer operation.
> >
> > Test: angle_end2end_tests --gtest_filter=*PBOCompressedSubImage*
> > angle_end2end_tests --gtest_filter=*PBOWithMultipleDraws*
> > dEQP-GLES3.functional.texture.specification.tex*image*d_pbo*
> > Bug: angleproject:3777
> > Change-Id: I3f271024a635be113202a16f8893a199c194172d
> > Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1906203
> > Reviewed-by: Cody Northrop <cnorthrop@google.com>
> > Commit-Queue: Mohan Maiya <m.maiya@samsung.com>
>
> TBR=cnorthrop@google.com,syoussefi@chromium.org,jmadill@chromium.org,m.maiya@samsung.com,b.schade@samsung.com
>
> # Not skipping CQ checks because original CL landed > 1 day ago.
>
> Bug: angleproject:3777
> Change-Id: I774655962e9ab5a866b9324002fb8edae8550834
> Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1939927
> Reviewed-by: Jamie Madill <jmadill@chromium.org>
> Commit-Queue: Jamie Madill <jmadill@chromium.org>
TBR=cnorthrop@google.com,syoussefi@chromium.org,jmadill@chromium.org,m.maiya@samsung.com,b.schade@samsung.com
Change-Id: I8560a2e70de230eac3256a1df5eb2ecaa6f26bcf
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: chromium:1027098, angleproject:3777
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1939852
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
diff --git a/src/tests/gl_tests/TextureTest.cpp b/src/tests/gl_tests/TextureTest.cpp
index 9193a52..d3f105f 100644
--- a/src/tests/gl_tests/TextureTest.cpp
+++ b/src/tests/gl_tests/TextureTest.cpp
@@ -16,6 +16,9 @@
constexpr GLuint kPixelTolerance = 1u;
constexpr GLfloat kPixelTolerance32F = 0.01f;
+// Single compressed ETC2 block of source pixels all set red
+constexpr uint8_t kCompressedImageETC2[] = {0x7E, 0x80, 0x04, 0x7F, 0x00, 0x07, 0xE0, 0x00};
+
// Take a pixel, and reset the components not covered by the format to default
// values. In particular, the default value for the alpha component is 255
// (1.0 as unsigned normalized fixed point value).
@@ -1419,6 +1422,32 @@
}
};
+class PBOCompressedTextureTest : public Texture2DTest
+{
+ protected:
+ PBOCompressedTextureTest() : Texture2DTest() {}
+
+ void testSetUp() override
+ {
+ TexCoordDrawTest::testSetUp();
+ glGenTextures(1, &mTexture2D);
+ glBindTexture(GL_TEXTURE_2D, mTexture2D);
+ EXPECT_GL_NO_ERROR();
+
+ setUpProgram();
+
+ glGenBuffers(1, &mPBO);
+ }
+
+ void testTearDown() override
+ {
+ glDeleteBuffers(1, &mPBO);
+ Texture2DTest::testTearDown();
+ }
+
+ GLuint mPBO;
+};
+
TEST_P(Texture2DTest, NegativeAPISubImage)
{
glBindTexture(GL_TEXTURE_2D, mTexture2D);
@@ -1763,53 +1792,176 @@
// initialized the image with a default color.
TEST_P(Texture2DTest, TexStorageWithPBO)
{
- if (IsGLExtensionEnabled("NV_pixel_buffer_object"))
+ // http://anglebug.com/4126
+ ANGLE_SKIP_TEST_IF(IsOSX() && IsOpenGL());
+
+ if (getClientMajorVersion() < 3)
{
- int width = getWindowWidth();
- int height = getWindowHeight();
-
- GLuint tex2D;
- glGenTextures(1, &tex2D);
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, tex2D);
-
- // Fill with red
- std::vector<GLubyte> pixels(3 * 16 * 16);
- for (size_t pixelId = 0; pixelId < 16 * 16; ++pixelId)
- {
- pixels[pixelId * 3 + 0] = 255;
- pixels[pixelId * 3 + 1] = 0;
- pixels[pixelId * 3 + 2] = 0;
- }
-
- // Read 16x16 region from red backbuffer to PBO
- GLuint pbo;
- glGenBuffers(1, &pbo);
- glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
- glBufferData(GL_PIXEL_UNPACK_BUFFER, 3 * 16 * 16, pixels.data(), GL_STATIC_DRAW);
-
- // ANGLE internally uses RGBA as the DirectX format for RGB images
- // therefore glTexStorage2DEXT initializes the image to a default color to get a consistent
- // alpha color. The data is kept in a CPU-side image and the image is marked as dirty.
- glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGB8, 16, 16);
-
- // Initializes the color of the upper-left 8x8 pixels, leaves the other pixels untouched.
- // glTexSubImage2D should take into account that the image is dirty.
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 8, 8, 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);
-
- setUpProgram();
-
- glUseProgram(mProgram);
- glUniform1i(mTexture2DUniformLocation, 0);
- drawQuad(mProgram, "position", 0.5f);
- glDeleteTextures(1, &tex2D);
- glDeleteBuffers(1, &pbo);
- EXPECT_GL_NO_ERROR();
- EXPECT_PIXEL_EQ(3 * width / 4, 3 * height / 4, 0, 0, 0, 255);
- EXPECT_PIXEL_EQ(width / 4, height / 4, 255, 0, 0, 255);
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_storage"));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_NV_pixel_buffer_object"));
}
+
+ const int width = getWindowWidth();
+ const int height = getWindowHeight();
+ const size_t pixelCount = width * height;
+ const int componentCount = 3;
+
+ GLuint tex2D;
+ glGenTextures(1, &tex2D);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, tex2D);
+
+ // Fill with red
+ std::vector<GLubyte> pixels(componentCount * pixelCount);
+ for (size_t pixelId = 0; pixelId < pixelCount; ++pixelId)
+ {
+ pixels[pixelId * componentCount + 0] = 255;
+ pixels[pixelId * componentCount + 1] = 0;
+ pixels[pixelId * componentCount + 2] = 0;
+ }
+
+ // Read 16x16 region from red backbuffer to PBO
+ GLuint pbo;
+ glGenBuffers(1, &pbo);
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
+ glBufferData(GL_PIXEL_UNPACK_BUFFER, componentCount * pixelCount, pixels.data(),
+ GL_STATIC_DRAW);
+
+ // ANGLE internally uses RGBA as the DirectX format for RGB images
+ // therefore glTexStorage2DEXT initializes the image to a default color to get a consistent
+ // alpha color. The data is kept in a CPU-side image and the image is marked as dirty.
+ glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGB8, width, height);
+
+ // Initializes the color of the upper-left quadrant of pixels, leaves the other pixels
+ // untouched. glTexSubImage2D should take into account that the image is dirty.
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width / 2, height / 2, 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);
+
+ setUpProgram();
+
+ glUseProgram(mProgram);
+ glUniform1i(mTexture2DUniformLocation, 0);
+ drawQuad(mProgram, "position", 0.5f);
+ glDeleteTextures(1, &tex2D);
+ glDeleteBuffers(1, &pbo);
+ EXPECT_GL_NO_ERROR();
+ EXPECT_PIXEL_EQ(3 * width / 4, 3 * height / 4, 0, 0, 0, 255);
+ EXPECT_PIXEL_EQ(width / 4, height / 4, 255, 0, 0, 255);
+}
+
+// Test that glTexSubImage2D combined with a PBO works properly after deleting the PBO
+// and drawing with the texture
+// Pseudo code for the follow test:
+// 1. Upload PBO to mTexture2D
+// 2. Delete PBO
+// 3. Draw with otherTexture (x5)
+// 4. Draw with mTexture2D
+// 5. Validate color output
+TEST_P(Texture2DTest, PBOWithMultipleDraws)
+{
+ if (getClientMajorVersion() < 3)
+ {
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_storage"));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_NV_pixel_buffer_object"));
+ }
+
+ const GLuint width = getWindowWidth();
+ const GLuint height = getWindowHeight();
+ const GLuint windowPixelCount = width * height;
+ std::vector<GLColor> pixelsRed(windowPixelCount, GLColor::red);
+ std::vector<GLColor> pixelsGreen(windowPixelCount, GLColor::green);
+
+ // Create secondary draw that does not use mTexture
+ const char *vertexShaderSource = getVertexShaderSource();
+ const char *fragmentShaderSource = getFragmentShaderSource();
+ ANGLE_GL_PROGRAM(otherProgram, vertexShaderSource, fragmentShaderSource);
+
+ GLint uniformLoc = glGetUniformLocation(otherProgram, getTextureUniformName());
+ ASSERT_NE(-1, uniformLoc);
+ glUseProgram(0);
+
+ // Create secondary Texture to draw with
+ GLTexture otherTexture;
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, otherTexture);
+ glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8, width, height);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE,
+ pixelsRed.data());
+ ASSERT_GL_NO_ERROR();
+
+ // Setup primary Texture
+ glBindTexture(GL_TEXTURE_2D, mTexture2D);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8, width, height);
+ ASSERT_GL_NO_ERROR();
+
+ // Setup PBO
+ GLuint pbo = 0;
+ glGenBuffers(1, &pbo);
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
+ glBufferData(GL_PIXEL_UNPACK_BUFFER, pixelsGreen.size() * 4u, pixelsGreen.data(),
+ GL_STATIC_DRAW);
+ ASSERT_GL_NO_ERROR();
+
+ // Write PBO to mTexture
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, 0);
+ ASSERT_GL_NO_ERROR();
+ // Delete PBO as ANGLE should be properly handling refcount of this buffer
+ glDeleteBuffers(1, &pbo);
+ pixelsGreen.clear();
+
+ // Do 5 draws not involving primary texture that the PBO updated
+ glUseProgram(otherProgram);
+ glUniform1i(uniformLoc, 0);
+ glBindTexture(GL_TEXTURE_2D, otherTexture);
+ drawQuad(otherProgram, "position", 0.5f);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glUseProgram(0);
+
+ glUseProgram(otherProgram);
+ glUniform1i(uniformLoc, 0);
+ glBindTexture(GL_TEXTURE_2D, otherTexture);
+ drawQuad(otherProgram, "position", 0.5f);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glUseProgram(0);
+
+ glUseProgram(otherProgram);
+ glUniform1i(uniformLoc, 0);
+ glBindTexture(GL_TEXTURE_2D, otherTexture);
+ drawQuad(otherProgram, "position", 0.5f);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glUseProgram(0);
+
+ glUseProgram(otherProgram);
+ glUniform1i(uniformLoc, 0);
+ glBindTexture(GL_TEXTURE_2D, otherTexture);
+ drawQuad(otherProgram, "position", 0.5f);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glUseProgram(0);
+ ASSERT_GL_NO_ERROR();
+
+ std::vector<GLColor> output(windowPixelCount, GLColor::black);
+ glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
+ output.data());
+ EXPECT_EQ(pixelsRed, output);
+
+ setUpProgram();
+ // Draw using PBO updated texture
+ glUseProgram(mProgram);
+ glUniform1i(mTexture2DUniformLocation, 0);
+ glBindTexture(GL_TEXTURE_2D, mTexture2D);
+ drawQuad(mProgram, "position", 0.5f);
+ ASSERT_GL_NO_ERROR();
+
+ std::vector<GLColor> actual(windowPixelCount, GLColor::black);
+ glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
+ actual.data());
+ // Value should be green as it was updated during PBO transfer to mTexture
+ std::vector<GLColor> expected(windowPixelCount, GLColor::green);
+ EXPECT_EQ(expected, actual);
}
// Tests CopySubImage for float formats
@@ -5676,6 +5828,65 @@
EXPECT_PIXEL_COLOR_EQ(width - 1, height - 1, color);
}
+// Test that uses glCompressedTexSubImage2D combined with a PBO
+TEST_P(PBOCompressedTextureTest, PBOCompressedSubImage)
+{
+ // ETC texture formats are not supported on Mac OpenGL. http://anglebug.com/3853
+ ANGLE_SKIP_TEST_IF(IsOSX() && IsDesktopOpenGL());
+ // http://anglebug.com/4115
+ ANGLE_SKIP_TEST_IF(IsAMD() && IsWindows() && IsDesktopOpenGL());
+ ANGLE_SKIP_TEST_IF(IsIntel() && IsWindows() && IsDesktopOpenGL());
+
+ if (getClientMajorVersion() < 3)
+ {
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_storage"));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_NV_pixel_buffer_object"));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_compressed_ETC2_RGB8_texture"));
+ }
+
+ const GLuint width = 4u;
+ const GLuint height = 4u;
+
+ setWindowWidth(width);
+ setWindowHeight(height);
+
+ // Setup primary Texture
+ glBindTexture(GL_TEXTURE_2D, mTexture2D);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+
+ if (getClientMajorVersion() < 3)
+ {
+ glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_COMPRESSED_RGB8_ETC2, width, height);
+ }
+ else
+ {
+ glTexStorage2D(GL_TEXTURE_2D, 1, GL_COMPRESSED_RGB8_ETC2, width, height);
+ }
+ ASSERT_GL_NO_ERROR();
+
+ // Setup PBO and fill it with a red
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, mPBO);
+ glBufferData(GL_PIXEL_UNPACK_BUFFER, width * height / 2u, kCompressedImageETC2, GL_STATIC_DRAW);
+ ASSERT_GL_NO_ERROR();
+
+ // Write PBO to mTexture
+ glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_COMPRESSED_RGB8_ETC2,
+ width * height / 2u, nullptr);
+ ASSERT_GL_NO_ERROR();
+
+ setUpProgram();
+ // Draw using PBO updated texture
+ glUseProgram(mProgram);
+ glUniform1i(mTexture2DUniformLocation, 0);
+ glBindTexture(GL_TEXTURE_2D, mTexture2D);
+ drawQuad(mProgram, "position", 0.5f);
+ ASSERT_GL_NO_ERROR();
+
+ EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::red);
+ ASSERT_GL_NO_ERROR();
+}
+
// Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against.
ANGLE_INSTANTIATE_TEST_ES2(Texture2DTest);
@@ -5714,5 +5925,6 @@
ANGLE_INSTANTIATE_TEST_ES3(Texture2DArrayIntegerTestES3);
ANGLE_INSTANTIATE_TEST_ES3(Texture3DIntegerTestES3);
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(Texture2DDepthTest);
+ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(PBOCompressedTextureTest);
} // anonymous namespace