Commit 9e3eec54 by Jamie Madill Committed by Commit Bot

Revert "Vulkan: Make DescriptorPoolHelper a Resource"

This reverts commit 5dcd29a6. Reason for revert: Breaking the ANGLE -> Chromium roller: https://chromium-review.googlesource.com/c/chromium/src/+/2496281 Original change's description: > Vulkan: Make DescriptorPoolHelper a Resource > > Descriptor pools need to live as long as the descriptor sets that are > allocated from them. Using Serials while building a command to judge a > pool's lifetime is prone to errors, since a command's Serial value > isn't known until the command is submitted, leading to deleting pools > too early relative to when the descriptor set is actually used. > > This CL updates DescriptorPoolHelper to inherit from Resource, so the > descriptor pools can be retain()'ed. This allows the Resource's counter > to indicate that a pool is in use until the command's Serial is known > and can be recorded to indicate when the command completes. This > prevents descriptor pools from being destroyed before the command > completes (while the descriptor sets are still in use), or even before > the command has been submitted. Destroying a descriptor pool resets all > of the descriptors that were allocated from it, which can trigger a > variety of VVL errors depending on when it's erroneously performed. > > This CL also adds the necessary retain() calls for the descriptor pools. > In particular, the pools need to be retained each time a cached > descriptor set that was allocated from it is re-used. This is relatively > simple with the current design, since we always clear the descriptor set > caches whenever a new pool is allocated, so the descriptor pool binding > is always accurate. > > Bug: angleproject:5030 > Test: MultithreadingTest::MultiContextDrawSmallDescriptorPools() > Change-Id: I5fdeeb46159448dfd679d7169e423048348be5ab > Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2437609 > Commit-Queue: Tim Van Patten <timvp@google.com> > Reviewed-by: Jamie Madill <jmadill@chromium.org> > Reviewed-by: Courtney Goeltzenleuchter <courtneygo@google.com> TBR=courtneygo@google.com,timvp@google.com,jmadill@chromium.org # Not skipping CQ checks because original CL landed > 1 day ago. Bug: angleproject:5030 Change-Id: I0fd6d9a0e1b0989b22368ef98652281288699deb Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2497222 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 2d6b6026
...@@ -4003,22 +4003,14 @@ angle::Result ContextVk::handleDirtyComputeDriverUniforms(const gl::Context *con ...@@ -4003,22 +4003,14 @@ angle::Result ContextVk::handleDirtyComputeDriverUniforms(const gl::Context *con
&mDriverUniforms[PipelineType::Compute]); &mDriverUniforms[PipelineType::Compute]);
} }
void ContextVk::handleDirtyDriverUniformsBindingImpl(vk::CommandBuffer *commandBuffer, void ContextVk::handleDirtyDriverUniformsBindingImpl(
VkPipelineBindPoint bindPoint, vk::CommandBuffer *commandBuffer,
DriverUniformsDescriptorSet *driverUniforms) VkPipelineBindPoint bindPoint,
const DriverUniformsDescriptorSet &driverUniforms)
{ {
// The descriptor pool that this descriptor set was allocated from needs to be retained when the
// descriptor set is used in a new command. Since the descriptor pools are specific to each
// ContextVk, we only need to retain them once to ensure the reference count and Serial are
// updated correctly.
if (!driverUniforms->descriptorPoolBinding.get().usedInRecordedCommands())
{
driverUniforms->descriptorPoolBinding.get().retain(&mResourceUseList);
}
commandBuffer->bindDescriptorSets( commandBuffer->bindDescriptorSets(
mExecutable->getPipelineLayout(), bindPoint, DescriptorSetIndex::DriverUniforms, 1, mExecutable->getPipelineLayout(), bindPoint, DescriptorSetIndex::DriverUniforms, 1,
&driverUniforms->descriptorSet, 1, &driverUniforms->dynamicOffset); &driverUniforms.descriptorSet, 1, &driverUniforms.dynamicOffset);
} }
angle::Result ContextVk::handleDirtyGraphicsDriverUniformsBinding(const gl::Context *context, angle::Result ContextVk::handleDirtyGraphicsDriverUniformsBinding(const gl::Context *context,
...@@ -4026,7 +4018,7 @@ angle::Result ContextVk::handleDirtyGraphicsDriverUniformsBinding(const gl::Cont ...@@ -4026,7 +4018,7 @@ angle::Result ContextVk::handleDirtyGraphicsDriverUniformsBinding(const gl::Cont
{ {
// Bind the driver descriptor set. // Bind the driver descriptor set.
handleDirtyDriverUniformsBindingImpl(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, handleDirtyDriverUniformsBindingImpl(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
&mDriverUniforms[PipelineType::Graphics]); mDriverUniforms[PipelineType::Graphics]);
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -4035,7 +4027,7 @@ angle::Result ContextVk::handleDirtyComputeDriverUniformsBinding(const gl::Conte ...@@ -4035,7 +4027,7 @@ angle::Result ContextVk::handleDirtyComputeDriverUniformsBinding(const gl::Conte
{ {
// Bind the driver descriptor set. // Bind the driver descriptor set.
handleDirtyDriverUniformsBindingImpl(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, handleDirtyDriverUniformsBindingImpl(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE,
&mDriverUniforms[PipelineType::Compute]); mDriverUniforms[PipelineType::Compute]);
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -4075,9 +4067,6 @@ angle::Result ContextVk::updateDriverUniformsDescriptorSet( ...@@ -4075,9 +4067,6 @@ angle::Result ContextVk::updateDriverUniformsDescriptorSet(
if (driverUniforms->descriptorSetCache.get(bufferSerial.getValue(), if (driverUniforms->descriptorSetCache.get(bufferSerial.getValue(),
&driverUniforms->descriptorSet)) &driverUniforms->descriptorSet))
{ {
// The descriptor pool that this descriptor set was allocated from needs to be retained each
// time the descriptor set is used in a new command.
driverUniforms->descriptorPoolBinding.get().retain(&mResourceUseList);
return angle::Result::Continue; return angle::Result::Continue;
} }
......
...@@ -908,7 +908,7 @@ class ContextVk : public ContextImpl, public vk::Context ...@@ -908,7 +908,7 @@ class ContextVk : public ContextImpl, public vk::Context
vk::CommandBufferHelper *commandBufferHelper); vk::CommandBufferHelper *commandBufferHelper);
void handleDirtyDriverUniformsBindingImpl(vk::CommandBuffer *commandBuffer, void handleDirtyDriverUniformsBindingImpl(vk::CommandBuffer *commandBuffer,
VkPipelineBindPoint bindPoint, VkPipelineBindPoint bindPoint,
DriverUniformsDescriptorSet *driverUniforms); const DriverUniformsDescriptorSet &driverUniforms);
angle::Result handleDirtyDescriptorSets(const gl::Context *context, angle::Result handleDirtyDescriptorSets(const gl::Context *context,
vk::CommandBuffer *commandBuffer); vk::CommandBuffer *commandBuffer);
angle::Result allocateDriverUniforms(size_t driverUniformsSize, angle::Result allocateDriverUniforms(size_t driverUniformsSize,
......
...@@ -378,12 +378,8 @@ angle::Result ProgramExecutableVk::allocUniformAndXfbDescriptorSet( ...@@ -378,12 +378,8 @@ angle::Result ProgramExecutableVk::allocUniformAndXfbDescriptorSet(
auto iter = mUniformsAndXfbDescriptorSetCache.find(xfbBufferDesc); auto iter = mUniformsAndXfbDescriptorSetCache.find(xfbBufferDesc);
if (iter != mUniformsAndXfbDescriptorSetCache.end()) if (iter != mUniformsAndXfbDescriptorSetCache.end())
{ {
*newDescriptorSetAllocated = false;
mDescriptorSets[ToUnderlying(DescriptorSetIndex::UniformsAndXfb)] = iter->second; mDescriptorSets[ToUnderlying(DescriptorSetIndex::UniformsAndXfb)] = iter->second;
// The descriptor pool that this descriptor set was allocated from needs to be retained each *newDescriptorSetAllocated = false;
// time the descriptor set is used in a new command.
mDescriptorPoolBindings[ToUnderlying(DescriptorSetIndex::UniformsAndXfb)].get().retain(
&contextVk->getResourceUseList());
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -1401,10 +1397,6 @@ angle::Result ProgramExecutableVk::updateTexturesDescriptorSet(ContextVk *contex ...@@ -1401,10 +1397,6 @@ angle::Result ProgramExecutableVk::updateTexturesDescriptorSet(ContextVk *contex
if (iter != mTextureDescriptorsCache.end()) if (iter != mTextureDescriptorsCache.end())
{ {
mDescriptorSets[ToUnderlying(DescriptorSetIndex::Texture)] = iter->second; mDescriptorSets[ToUnderlying(DescriptorSetIndex::Texture)] = iter->second;
// The descriptor pool that this descriptor set was allocated from needs to be retained each
// time the descriptor set is used in a new command.
mDescriptorPoolBindings[ToUnderlying(DescriptorSetIndex::Texture)].get().retain(
&contextVk->getResourceUseList());
return angle::Result::Continue; return angle::Result::Continue;
} }
......
...@@ -200,7 +200,6 @@ ANGLE_INLINE void Resource::retain(ResourceUseList *resourceUseList) ...@@ -200,7 +200,6 @@ ANGLE_INLINE void Resource::retain(ResourceUseList *resourceUseList)
// Store reference in resource list. // Store reference in resource list.
resourceUseList->add(mUse); resourceUseList->add(mUse);
} }
} // namespace vk } // namespace vk
} // namespace rx } // namespace rx
......
...@@ -2631,6 +2631,7 @@ angle::Result UtilsVk::allocateDescriptorSet(ContextVk *contextVk, ...@@ -2631,6 +2631,7 @@ angle::Result UtilsVk::allocateDescriptorSet(ContextVk *contextVk,
.get() .get()
.ptr(), .ptr(),
1, bindingOut, descriptorSetOut)); 1, bindingOut, descriptorSetOut));
bindingOut->get().updateSerial(contextVk->getCurrentQueueSerial());
return angle::Result::Continue; return angle::Result::Continue;
} }
......
...@@ -1874,7 +1874,7 @@ angle::Result DescriptorPoolHelper::init(ContextVk *contextVk, ...@@ -1874,7 +1874,7 @@ angle::Result DescriptorPoolHelper::init(ContextVk *contextVk,
{ {
if (mDescriptorPool.valid()) if (mDescriptorPool.valid())
{ {
ASSERT(!isCurrentlyInUse(contextVk->getLastCompletedQueueSerial())); // This could be improved by recycling the descriptor pool.
mDescriptorPool.destroy(contextVk->getDevice()); mDescriptorPool.destroy(contextVk->getDevice());
} }
...@@ -1927,9 +1927,6 @@ angle::Result DescriptorPoolHelper::allocateSets(ContextVk *contextVk, ...@@ -1927,9 +1927,6 @@ angle::Result DescriptorPoolHelper::allocateSets(ContextVk *contextVk,
ANGLE_VK_TRY(contextVk, mDescriptorPool.allocateDescriptorSets(contextVk->getDevice(), ANGLE_VK_TRY(contextVk, mDescriptorPool.allocateDescriptorSets(contextVk->getDevice(),
allocInfo, descriptorSetsOut)); allocInfo, descriptorSetsOut));
// The pool is still in use every time a new descriptor set is allocated from it.
retain(&contextVk->getResourceUseList());
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -1971,7 +1968,6 @@ void DynamicDescriptorPool::destroy(VkDevice device) ...@@ -1971,7 +1968,6 @@ void DynamicDescriptorPool::destroy(VkDevice device)
} }
mDescriptorPools.clear(); mDescriptorPools.clear();
mCurrentPoolIndex = 0;
mCachedDescriptorSetLayout = VK_NULL_HANDLE; mCachedDescriptorSetLayout = VK_NULL_HANDLE;
} }
...@@ -1985,7 +1981,6 @@ void DynamicDescriptorPool::release(ContextVk *contextVk) ...@@ -1985,7 +1981,6 @@ void DynamicDescriptorPool::release(ContextVk *contextVk)
} }
mDescriptorPools.clear(); mDescriptorPools.clear();
mCurrentPoolIndex = 0;
mCachedDescriptorSetLayout = VK_NULL_HANDLE; mCachedDescriptorSetLayout = VK_NULL_HANDLE;
} }
...@@ -2010,6 +2005,15 @@ angle::Result DynamicDescriptorPool::allocateSetsAndGetInfo( ...@@ -2010,6 +2005,15 @@ angle::Result DynamicDescriptorPool::allocateSetsAndGetInfo(
*newPoolAllocatedOut = true; *newPoolAllocatedOut = true;
} }
// Make sure the old binding knows the descriptor sets can still be in-use. We only need
// to update the serial when we move to a new pool. This is because we only check serials
// when we move to a new pool.
if (bindingOut->valid())
{
Serial currentSerial = contextVk->getCurrentQueueSerial();
bindingOut->get().updateSerial(currentSerial);
}
bindingOut->set(mDescriptorPools[mCurrentPoolIndex]); bindingOut->set(mDescriptorPools[mCurrentPoolIndex]);
} }
...@@ -2021,11 +2025,10 @@ angle::Result DynamicDescriptorPool::allocateNewPool(ContextVk *contextVk) ...@@ -2021,11 +2025,10 @@ angle::Result DynamicDescriptorPool::allocateNewPool(ContextVk *contextVk)
{ {
bool found = false; bool found = false;
Serial lastCompletedSerial = contextVk->getLastCompletedQueueSerial();
for (size_t poolIndex = 0; poolIndex < mDescriptorPools.size(); ++poolIndex) for (size_t poolIndex = 0; poolIndex < mDescriptorPools.size(); ++poolIndex)
{ {
if (!mDescriptorPools[poolIndex]->isReferenced() && if (!mDescriptorPools[poolIndex]->isReferenced() &&
!mDescriptorPools[poolIndex]->get().isCurrentlyInUse(lastCompletedSerial)) !contextVk->isSerialInUse(mDescriptorPools[poolIndex]->get().getSerial()))
{ {
mCurrentPoolIndex = poolIndex; mCurrentPoolIndex = poolIndex;
found = true; found = true;
......
...@@ -237,15 +237,18 @@ class DynamicShadowBuffer : public angle::NonCopyable ...@@ -237,15 +237,18 @@ class DynamicShadowBuffer : public angle::NonCopyable
// Uses DescriptorPool to allocate descriptor sets as needed. If a descriptor pool becomes full, we // Uses DescriptorPool to allocate descriptor sets as needed. If a descriptor pool becomes full, we
// allocate new pools internally as needed. RendererVk takes care of the lifetime of the discarded // allocate new pools internally as needed. RendererVk takes care of the lifetime of the discarded
// pools. Note that we used a fixed layout for descriptor pools in ANGLE. // pools. Note that we used a fixed layout for descriptor pools in ANGLE. Uniform buffers must
// use set zero and combined Image Samplers must use set 1. We conservatively count each new set
// using the maximum number of descriptor sets and buffers with each allocation. Currently: 2
// (Vertex/Fragment) uniform buffers and 64 (MAX_ACTIVE_TEXTURES) image/samplers.
// Shared handle to a descriptor pool. Each helper is allocated from the dynamic descriptor pool. // Shared handle to a descriptor pool. Each helper is allocated from the dynamic descriptor pool.
// Can be used to share descriptor pools between multiple ProgramVks and the ContextVk. // Can be used to share descriptor pools between multiple ProgramVks and the ContextVk.
class DescriptorPoolHelper : public Resource class DescriptorPoolHelper
{ {
public: public:
DescriptorPoolHelper(); DescriptorPoolHelper();
~DescriptorPoolHelper() override; ~DescriptorPoolHelper();
bool valid() { return mDescriptorPool.valid(); } bool valid() { return mDescriptorPool.valid(); }
...@@ -261,9 +264,14 @@ class DescriptorPoolHelper : public Resource ...@@ -261,9 +264,14 @@ class DescriptorPoolHelper : public Resource
uint32_t descriptorSetCount, uint32_t descriptorSetCount,
VkDescriptorSet *descriptorSetsOut); VkDescriptorSet *descriptorSetsOut);
void updateSerial(Serial serial) { mMostRecentSerial = serial; }
Serial getSerial() const { return mMostRecentSerial; }
private: private:
uint32_t mFreeDescriptorSets; uint32_t mFreeDescriptorSets;
DescriptorPool mDescriptorPool; DescriptorPool mDescriptorPool;
Serial mMostRecentSerial;
}; };
using RefCountedDescriptorPoolHelper = RefCounted<DescriptorPoolHelper>; using RefCountedDescriptorPoolHelper = RefCounted<DescriptorPoolHelper>;
......
...@@ -89,6 +89,7 @@ angle_end2end_tests_sources = [ ...@@ -89,6 +89,7 @@ angle_end2end_tests_sources = [
"gl_tests/MultisampleCompatibilityTest.cpp", "gl_tests/MultisampleCompatibilityTest.cpp",
"gl_tests/MultisampleTest.cpp", "gl_tests/MultisampleTest.cpp",
"gl_tests/MultisampledRenderToTextureTest.cpp", "gl_tests/MultisampledRenderToTextureTest.cpp",
"gl_tests/MultithreadingTest.cpp",
"gl_tests/MultiviewDrawTest.cpp", "gl_tests/MultiviewDrawTest.cpp",
"gl_tests/ObjectAllocationTest.cpp", "gl_tests/ObjectAllocationTest.cpp",
"gl_tests/OcclusionQueriesTest.cpp", "gl_tests/OcclusionQueriesTest.cpp",
......
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
angle_white_box_tests_sources = [ angle_white_box_tests_sources = [
"egl_tests/EGLFeatureControlTest.cpp", "egl_tests/EGLFeatureControlTest.cpp",
"gl_tests/FormatPrintTest.cpp", "gl_tests/FormatPrintTest.cpp",
"gl_tests/MultithreadingTest.cpp",
"test_utils/ANGLETest.cpp", "test_utils/ANGLETest.cpp",
"test_utils/ANGLETest.h", "test_utils/ANGLETest.h",
"util_tests/PrintSystemInfoTest.cpp", "util_tests/PrintSystemInfoTest.cpp",
......
...@@ -14,51 +14,22 @@ ...@@ -14,51 +14,22 @@
#include <mutex> #include <mutex>
#include <thread> #include <thread>
#include "libANGLE/renderer/vulkan/vk_helpers.h"
namespace angle namespace angle
{ {
constexpr char kExtensionName[] = "GL_ANGLE_get_image";
static constexpr int kSize = 256;
class MultithreadingTest : public ANGLETest class MultithreadingTest : public ANGLETest
{ {
protected: protected:
MultithreadingTest() MultithreadingTest()
{ {
setWindowWidth(kSize); setWindowWidth(128);
setWindowHeight(kSize); setWindowHeight(128);
setConfigRedBits(8); setConfigRedBits(8);
setConfigGreenBits(8); setConfigGreenBits(8);
setConfigBlueBits(8); setConfigBlueBits(8);
setConfigAlphaBits(8); setConfigAlphaBits(8);
} }
void testSetUp() override
{
mMaxSetsPerPool = rx::vk::DynamicDescriptorPool::GetMaxSetsPerPoolForTesting();
mMaxSetsPerPoolMultiplier =
rx::vk::DynamicDescriptorPool::GetMaxSetsPerPoolMultiplierForTesting();
}
void testTearDown() override
{
rx::vk::DynamicDescriptorPool::SetMaxSetsPerPoolForTesting(mMaxSetsPerPool);
rx::vk::DynamicDescriptorPool::SetMaxSetsPerPoolMultiplierForTesting(
mMaxSetsPerPoolMultiplier);
}
static constexpr uint32_t kMaxSetsForTesting = 1;
static constexpr uint32_t kMaxSetsMultiplierForTesting = 1;
void limitMaxSets()
{
rx::vk::DynamicDescriptorPool::SetMaxSetsPerPoolForTesting(kMaxSetsForTesting);
rx::vk::DynamicDescriptorPool::SetMaxSetsPerPoolMultiplierForTesting(
kMaxSetsMultiplierForTesting);
}
void runMultithreadedGLTest( void runMultithreadedGLTest(
std::function<void(EGLSurface surface, size_t threadIndex)> testBody, std::function<void(EGLSurface surface, size_t threadIndex)> testBody,
size_t threadCount) size_t threadCount)
...@@ -69,7 +40,7 @@ class MultithreadingTest : public ANGLETest ...@@ -69,7 +40,7 @@ class MultithreadingTest : public ANGLETest
EGLDisplay dpy = window->getDisplay(); EGLDisplay dpy = window->getDisplay();
EGLConfig config = window->getConfig(); EGLConfig config = window->getConfig();
constexpr EGLint kPBufferSize = kSize; constexpr EGLint kPBufferSize = 256;
std::vector<std::thread> threads(threadCount); std::vector<std::thread> threads(threadCount);
for (size_t threadIdx = 0; threadIdx < threadCount; threadIdx++) for (size_t threadIdx = 0; threadIdx < threadCount; threadIdx++)
...@@ -116,10 +87,6 @@ class MultithreadingTest : public ANGLETest ...@@ -116,10 +87,6 @@ class MultithreadingTest : public ANGLETest
thread.join(); thread.join();
} }
} }
private:
uint32_t mMaxSetsPerPool;
uint32_t mMaxSetsPerPoolMultiplier;
}; };
// Test that it's possible to make one context current on different threads // Test that it's possible to make one context current on different threads
...@@ -235,88 +202,7 @@ TEST_P(MultithreadingTest, MultiContextDraw) ...@@ -235,88 +202,7 @@ TEST_P(MultithreadingTest, MultiContextDraw)
runMultithreadedGLTest(testBody, 4); runMultithreadedGLTest(testBody, 4);
} }
// Test that multiple threads can draw and readback pixels successfully at the same time with small // Test that multiple threads can draw and read back pixels correctly.
// descriptor pools.
TEST_P(MultithreadingTest, MultiContextDrawSmallDescriptorPools)
{
ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
// Verify the extension is enabled.
ASSERT_TRUE(IsGLExtensionEnabled(kExtensionName));
// Must be before program creation to limit the descriptor pool sizes when creating the pipeline
// layout.
limitMaxSets();
auto testBody = [](EGLSurface surface, size_t thread) {
constexpr size_t kIterationsPerThread = 16;
constexpr size_t kDrawsPerIteration = 16;
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
glUseProgram(program);
GLTexture copyTexture;
glBindTexture(GL_TEXTURE_2D, copyTexture);
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_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
ASSERT_GL_NO_ERROR();
GLint colorLocation = glGetUniformLocation(program, essl1_shaders::ColorUniform());
auto quadVertices = GetQuadVertices();
GLBuffer vertexBuffer;
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * 6, quadVertices.data(), GL_STATIC_DRAW);
GLint positionLocation = glGetAttribLocation(program, essl1_shaders::PositionAttrib());
glEnableVertexAttribArray(positionLocation);
glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
// Pack pixels tightly.
glPixelStorei(GL_PACK_ALIGNMENT, 1);
std::vector<GLColor> actualData(kSize * kSize);
for (size_t iteration = 0; iteration < kIterationsPerThread; iteration++)
{
// Base the clear color on the thread and iteration indexes so every clear color is
// unique
const GLColor color(static_cast<GLubyte>(thread % 255),
static_cast<GLubyte>(iteration % 255), 0, 255);
const angle::Vector4 floatColor = color.toNormalizedVector();
glUniform4fv(colorLocation, 1, floatColor.data());
for (size_t draw = 0; draw < kDrawsPerIteration; draw++)
{
glDrawArrays(GL_TRIANGLES, 0, 6);
ASSERT_GL_NO_ERROR();
// Perform CopyTexImage2D
glBindTexture(GL_TEXTURE_2D, copyTexture);
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, kSize, kSize, 0);
ASSERT_GL_NO_ERROR();
}
// There's a good chance this test will crash before failing, but if not we'll try and
// verify the contents of the copied texture.
// TODO(http://anglebug.com/5204): Need to re-enable for Linux/Windows.
if (IsGLExtensionEnabled(kExtensionName) && !(IsLinux() || IsWindows()))
{
// Verify glCopyTexImage2D() was successful.
glGetTexImageANGLE(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, actualData.data());
EXPECT_GL_NO_ERROR();
EXPECT_EQ(color, actualData[0]);
}
}
};
runMultithreadedGLTest(testBody, 4);
}
// Test that multiple threads can draw and read back pixels correctly with small descriptor pools.
// Using eglSwapBuffers stresses race conditions around use of QueueSerials. // Using eglSwapBuffers stresses race conditions around use of QueueSerials.
TEST_P(MultithreadingTest, MultiContextDrawWithSwapBuffers) TEST_P(MultithreadingTest, MultiContextDrawWithSwapBuffers)
{ {
...@@ -480,8 +366,6 @@ ANGLE_INSTANTIATE_TEST(MultithreadingTest, ...@@ -480,8 +366,6 @@ ANGLE_INSTANTIATE_TEST(MultithreadingTest,
WithNoVirtualContexts(ES2_OPENGL()), WithNoVirtualContexts(ES2_OPENGL()),
WithNoVirtualContexts(ES3_OPENGL()), WithNoVirtualContexts(ES3_OPENGL()),
WithNoVirtualContexts(ES2_OPENGLES()), WithNoVirtualContexts(ES2_OPENGLES()),
WithNoVirtualContexts(ES3_OPENGLES()), WithNoVirtualContexts(ES3_OPENGLES()));
WithNoVirtualContexts(ES2_VULKAN()),
WithNoVirtualContexts(ES3_VULKAN()));
} // namespace angle } // namespace angle
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment