Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 41c93c5

Browse files
Mohan MaiyaCommit Bot
authored andcommitted
Vulkan: Bug fix in atomic counter buffer count calculation
When binding a new atomic counter buffer to a slot it is necessary to take into account the previous binding of that slot. This rectifies a bug introduced in f7b607c Bug: angleproject:3566 Test: angle_unittests.exe --gtest_filter=AtomicCounterBufferTest31.AtomicCounterBuffer* Change-Id: If78954d27c3345e8620294a84e839058d7dd7b9a Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2388431 Commit-Queue: Mohan Maiya <[email protected]> Reviewed-by: Tim Van Patten <[email protected]> Reviewed-by: Shahbaz Youssefi <[email protected]>
1 parent d4b029e commit 41c93c5

File tree

3 files changed

+146
-5
lines changed

3 files changed

+146
-5
lines changed

src/libANGLE/State.cpp

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,7 @@ State::State(const State *shareContextState,
345345
mVertexArray(nullptr),
346346
mActiveSampler(0),
347347
mTexturesIncompatibleWithSamplers(0),
348+
mValidAtomicCounterBufferCount(0),
348349
mPrimitiveRestart(false),
349350
mDebug(debug),
350351
mMultiSampling(false),
@@ -443,7 +444,6 @@ void State::initialize(Context *context)
443444
caps.maxCombinedTextureImageUnits);
444445

445446
mAtomicCounterBuffers.resize(caps.maxAtomicCounterBufferBindings);
446-
mValidAtomicCounterBufferCount = 0;
447447
mShaderStorageBuffers.resize(caps.maxShaderStorageBufferBindings);
448448
mImageUnits.resize(caps.maxImageUnits);
449449
}
@@ -1973,12 +1973,21 @@ angle::Result State::setIndexedBufferBinding(const Context *context,
19731973
size);
19741974
break;
19751975
case BufferBinding::AtomicCounter:
1976-
UpdateIndexedBufferBinding(context, &mAtomicCounterBuffers[index], buffer, target,
1977-
offset, size);
1978-
if (buffer)
1976+
if (!mAtomicCounterBuffers[index].get() && buffer)
19791977
{
1978+
// going from an invalid binding to a valid one, increment the count
19801979
mValidAtomicCounterBufferCount++;
1980+
ASSERT(mValidAtomicCounterBufferCount <=
1981+
static_cast<uint32_t>(getCaps().maxAtomicCounterBufferBindings));
1982+
}
1983+
else if (mAtomicCounterBuffers[index].get() && !buffer)
1984+
{
1985+
// going from a valid binding to an invalid one, decrement the count
1986+
mValidAtomicCounterBufferCount--;
1987+
ASSERT(mValidAtomicCounterBufferCount >= 0);
19811988
}
1989+
UpdateIndexedBufferBinding(context, &mAtomicCounterBuffers[index], buffer, target,
1990+
offset, size);
19821991
break;
19831992
case BufferBinding::ShaderStorage:
19841993
UpdateIndexedBufferBinding(context, &mShaderStorageBuffers[index], buffer, target,
@@ -2051,6 +2060,7 @@ angle::Result State::detachBuffer(Context *context, const Buffer *buffer)
20512060
{
20522061
UpdateIndexedBufferBinding(context, &buf, nullptr, BufferBinding::AtomicCounter, 0, 0);
20532062
mValidAtomicCounterBufferCount--;
2063+
ASSERT(mValidAtomicCounterBufferCount >= 0);
20542064
}
20552065
}
20562066

src/libANGLE/State.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1034,7 +1034,7 @@ class State : angle::NonCopyable
10341034

10351035
BufferVector mUniformBuffers;
10361036
BufferVector mAtomicCounterBuffers;
1037-
size_t mValidAtomicCounterBufferCount;
1037+
uint32_t mValidAtomicCounterBufferCount;
10381038
BufferVector mShaderStorageBuffers;
10391039

10401040
BindingPointer<TransformFeedback> mTransformFeedback;

src/tests/gl_tests/AtomicCounterBufferTest.cpp

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,137 @@ TEST_P(AtomicCounterBufferTest31, AtomicCounterRead)
185185
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
186186
}
187187

188+
// Updating atomic counter buffer's offsets was optimized based on a count of valid bindings.
189+
// This test will fail if there are bugs in how we count valid bindings.
190+
TEST_P(AtomicCounterBufferTest31, AtomicCounterBufferRangeRead)
191+
{
192+
// Skipping due to a bug on the Qualcomm driver.
193+
// http://anglebug.com/3726
194+
ANGLE_SKIP_TEST_IF(IsNexus5X());
195+
196+
// Skipping due to a bug on the Qualcomm Vulkan Android driver.
197+
// http://anglebug.com/3726
198+
ANGLE_SKIP_TEST_IF(IsAndroid() && IsVulkan());
199+
200+
// Skipping test while we work on enabling atomic counter buffer support in th D3D renderer.
201+
// http://anglebug.com/1729
202+
ANGLE_SKIP_TEST_IF(IsD3D11());
203+
204+
constexpr char kFS[] =
205+
"#version 310 es\n"
206+
"precision highp float;\n"
207+
"layout(binding = 0, offset = 4) uniform atomic_uint ac;\n"
208+
"out highp vec4 my_color;\n"
209+
"void main()\n"
210+
"{\n"
211+
" my_color = vec4(0.0);\n"
212+
" uint a1 = atomicCounter(ac);\n"
213+
" if (a1 == 3u) my_color = vec4(1.0);\n"
214+
"}\n";
215+
216+
ANGLE_GL_PROGRAM(program, essl31_shaders::vs::Simple(), kFS);
217+
218+
glUseProgram(program.get());
219+
220+
// The initial value of counter 'ac' is 3u.
221+
unsigned int bufferData[] = {0u, 0u, 0u, 0u, 0u, 11u, 3u, 1u};
222+
constexpr GLintptr kOffset = 20;
223+
GLint maxAtomicCounterBuffers = 0;
224+
GLBuffer atomicCounterBuffer;
225+
226+
glGetIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS, &maxAtomicCounterBuffers);
227+
// Repeatedly bind the same buffer (GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS + 1) times
228+
// A bug in counting valid atomic counter buffers will cause a crash when we
229+
// exceed GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS
230+
for (int32_t i = 0; i < maxAtomicCounterBuffers + 1; i++)
231+
{
232+
glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicCounterBuffer);
233+
glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(bufferData), bufferData, GL_STATIC_DRAW);
234+
glBindBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, atomicCounterBuffer, kOffset,
235+
sizeof(bufferData) - kOffset);
236+
}
237+
238+
drawQuad(program.get(), essl31_shaders::PositionAttrib(), 0.0f);
239+
ASSERT_GL_NO_ERROR();
240+
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
241+
}
242+
243+
// Updating atomic counter buffer's offsets was optimized based on a count of valid bindings.
244+
// Repeatedly bind/unbind buffers across available binding points. The test will fail if
245+
// there are bugs in how we count valid bindings.
246+
TEST_P(AtomicCounterBufferTest31, AtomicCounterBufferRepeatedBindUnbind)
247+
{
248+
// Skipping due to a bug on the Qualcomm Vulkan Android driver.
249+
// http://anglebug.com/3726
250+
ANGLE_SKIP_TEST_IF(IsAndroid() && IsVulkan());
251+
252+
// Skipping test while we work on enabling atomic counter buffer support in th D3D renderer.
253+
// http://anglebug.com/1729
254+
ANGLE_SKIP_TEST_IF(IsD3D11());
255+
256+
constexpr char kFS[] =
257+
"#version 310 es\n"
258+
"precision highp float;\n"
259+
"layout(binding = 0, offset = 4) uniform atomic_uint ac;\n"
260+
"out highp vec4 my_color;\n"
261+
"void main()\n"
262+
"{\n"
263+
" my_color = vec4(0.0);\n"
264+
" uint a1 = atomicCounter(ac);\n"
265+
" if (a1 == 3u) my_color = vec4(1.0);\n"
266+
"}\n";
267+
268+
ANGLE_GL_PROGRAM(program, essl31_shaders::vs::Simple(), kFS);
269+
270+
glUseProgram(program.get());
271+
272+
constexpr int32_t kBufferCount = 16;
273+
// The initial value of counter 'ac' is 3u.
274+
unsigned int bufferData[3] = {11u, 3u, 1u};
275+
GLBuffer atomicCounterBuffer[kBufferCount];
276+
// Populate atomicCounterBuffer[0] with valid data and the rest with nullptr
277+
for (int32_t bufferIndex = 0; bufferIndex < kBufferCount; bufferIndex++)
278+
{
279+
glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicCounterBuffer[bufferIndex]);
280+
glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(bufferData),
281+
(bufferIndex == 0) ? bufferData : nullptr, GL_STATIC_DRAW);
282+
}
283+
284+
GLint maxAtomicCounterBuffers = 0;
285+
glGetIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS, &maxAtomicCounterBuffers);
286+
287+
// Cycle through multiple buffers
288+
for (int32_t i = 0; i < kBufferCount; i++)
289+
{
290+
constexpr int32_t kBufferIndices[kBufferCount] = {7, 12, 15, 5, 13, 14, 1, 2,
291+
0, 6, 4, 9, 8, 11, 3, 10};
292+
int32_t bufferIndex = kBufferIndices[i];
293+
294+
// Randomly bind/unbind buffers to/from different binding points,
295+
// capped by GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS
296+
for (int32_t bufferCount = 0; bufferCount < maxAtomicCounterBuffers; bufferCount++)
297+
{
298+
constexpr uint32_t kBindingSlotsSize = kBufferCount;
299+
constexpr uint32_t kBindingSlots[kBindingSlotsSize] = {1, 3, 4, 14, 15, 9, 0, 6,
300+
12, 11, 8, 5, 10, 2, 7, 13};
301+
302+
uint32_t bindingSlotIndex = bufferCount % kBindingSlotsSize;
303+
uint32_t bindingSlot = kBindingSlots[bindingSlotIndex];
304+
uint32_t bindingPoint = bindingSlot % maxAtomicCounterBuffers;
305+
bool even = (bufferCount % 2 == 0);
306+
int32_t bufferId = (even) ? 0 : atomicCounterBuffer[bufferIndex];
307+
308+
glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, bindingPoint, bufferId);
309+
}
310+
}
311+
312+
// Bind atomicCounterBuffer[0] to slot 0 and verify result
313+
glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, atomicCounterBuffer[0]);
314+
drawQuad(program.get(), essl31_shaders::PositionAttrib(), 0.0f);
315+
ASSERT_GL_NO_ERROR();
316+
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
317+
}
318+
188319
// Test atomic counter increment and decrement.
189320
TEST_P(AtomicCounterBufferTest31, AtomicCounterIncrementAndDecrement)
190321
{

0 commit comments

Comments
 (0)