Atomic Counter

Atomic Counter是一个缓存对象,存储着一个或者多个unsigned int的变量值。在GLSL着色器有着特定的原子操作(单一的,不可再分的操作)。

  1. atomicCounterIncrement 原子计数+1
  2. atomicCounterDecrement 原子计数-1

Atomic Counter可以用来控制片元的执行,避免对同一块内存区域同时操作。原子计数器表明当前片元在执行任务时,不能被其他任务打断,保证内存中数据修改的正确性。

简单示例,片元执行顺序的可视化。

初始化

    glGenBuffers(1, &m_AtomicBuffer);
    glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_AtomicBuffer);
    glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(GLuint)*3, NULL, GL_DYNAMIC_DRAW);
    glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);

更新

每一帧重绘时,需要重置GL_ATOMIC_COUNTER_BUFFER的值,两种方式可以修改其值。

    glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_AtomicBuffer);
    GLuint* pAtomicCounter = (GLuint*)glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint)*3, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
    _ASSERT(pAtomicCounter);
    memset(pAtomicCounter, 0, sizeof(GLuint)*3);
    glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);

    //第二种方式,glSubBufferData
    //glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_AtomicBuffer);
    //GLuint Value[3] = {0, 0, 0};
    //glBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint)*3, Value);
    //glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);

Fragment Shader

#version 450 core

layout (binding = 0, offset = 0) uniform atomic_uint aRed;
layout (binding = 0, offset = 4) uniform atomic_uint aGreen;
layout (binding = 0, offset = 8) uniform atomic_uint aBlue;

uniform float fNumPixels = 1.0/(1024*768);

out vec4 FragColor;

void main()
{
    float R = atomicCounterIncrement(aRed) * fNumPixels;
    float G = atomicCounterIncrement(aGreen) * fNumPixels;
    float B = atomicCounterIncrement(aBlue) * fNumPixels;

    FragColor = vec4(R, G, B, 1.0);
}

绑定到GL_ATOMIC_COUNTER_BUFFER 0号绑定点位置,glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, m_AtomicBuffer);

通过建立一个GL_ATOMIC_COUNTER_BUFFER,里面储存3个uint变量值,随着源自计数器的增加,颜色输出逐渐变白的过程。

这里写图片描述

参考资料

【1】https://www.opengl.org/wiki/Atomic_Counter
【2】http://blog.csdn.net/csxiaoshui/article/details/33740065
【3】http://www.geeks3d.com/20120309/opengl-4-2-atomic-counter-demo-rendering-order-of-fragments/
【4】http://www.lighthouse3d.com/tutorials/opengl-atomic-counters/

### Atomic Operations in Programming and Concurrency In concurrent programming, atomic operations play a crucial role in ensuring data integrity when multiple threads access shared resources simultaneously. An operation is considered atomic if it completes instantly from the perspective of other concurrently executing threads or processes. Atomicity guarantees that an operation will not be interrupted once started until completion. This prevents race conditions where two or more threads attempt to modify the same variable at nearly the same time leading to unpredictable outcomes[^1]. #### Usage of Atomics To handle synchronization without traditional locks, C++ provides `std::atomic` types within its standard library. These allow performing read-modify-write actions atomically: ```cpp #include <atomic> #include <thread> std::atomic<int> counter{0}; void increment_counter() { for (int i = 0; i < 1000; ++i) { counter.fetch_add(1, std::memory_order_relaxed); } } int main() { const unsigned thread_count = 10; std::vector<std::thread> threads; for (unsigned i = 0; i < thread_count; ++i) { threads.emplace_back(increment_counter); } for (auto& t : threads) { t.join(); } // Expected value should be close to 10 * 1000 = 10000 std::cout << "Counter: " << counter.load() << '\n'; } ``` The above example demonstrates how `fetch_add()` method performs addition as an indivisible action across different threads safely avoiding any potential conflicts during updates[^2]. #### Memory Ordering Constraints When working with atomics, memory ordering constraints dictate what changes become visible to other threads after an atomic operation has completed. The options range from very weak (`memory_order_relaxed`) allowing maximum performance but minimal visibility guarantees up to fully synchronized (`memory_order_seq_cst`) providing strictest consistency between all involved parties[^3]. For instance, setting appropriate barriers ensures correct program behavior even under relaxed orderings by preventing certain instructions from being reordered around these points thus preserving intended semantics despite optimizations performed by compilers or hardware architectures. #### Benefits Over Traditional Synchronization Mechanisms Using atomic variables offers several advantages over conventional locking mechanisms such as mutexes including better scalability due to reduced contention among threads accessing non-overlapping parts of state space independently alongside lower overhead costs associated with acquiring/releases compared to full-fledged mutual exclusions constructs[^4]. However, developers must carefully design algorithms taking into account possible limitations imposed by chosen levels of coarseness versus fineness regarding granularity choices made concerning protected regions since overly broad scopes could negate some benefits derived otherwise through finer control offered here instead[^5].
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值