32    return (value + bytes - 1) & ~T(bytes - 1);
 
 
   47    std::vector<uint16_t> m_data;
 
 
   54    glGenBuffers(1, &m_buffer);
 
 
   60    glDeleteBuffers(1, &m_buffer);
 
 
   66    if (count <= m_count) {
 
   69    Q_ASSERT(m_count * 2 < std::numeric_limits<uint16_t>::max() / 4);
 
   70    const size_t oldCount = m_count;
 
   72    m_data.reserve(m_count * 6);
 
   73    for (
size_t i = oldCount; i < m_count; i++) {
 
   74        const uint16_t offset = i * 4;
 
   75        m_data[i * 6 + 0] = offset + 1;
 
   76        m_data[i * 6 + 1] = offset + 0;
 
   77        m_data[i * 6 + 2] = offset + 3;
 
   78        m_data[i * 6 + 3] = offset + 3;
 
   79        m_data[i * 6 + 4] = offset + 2;
 
   80        m_data[i * 6 + 5] = offset + 1;
 
   82    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_buffer);
 
   83    glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_count * 
sizeof(uint16_t), m_data.data(), GL_STATIC_DRAW);
 
 
   88    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_buffer);
 
 
  110        glGetSynciv(
sync, GL_SYNC_STATUS, 1, 
nullptr, &value);
 
  111        return value == GL_SIGNALED;
 
 
 
  115static void deleteAll(std::deque<BufferFence> &fences)
 
  117    for (
const BufferFence &fence : fences) {
 
  118        glDeleteSync(fence.sync);
 
  126template<
size_t Count>
 
  137        m_array[m_index] = size;
 
  138        m_index = (m_index + 1) % Count;
 
 
  144        for (
size_t size : m_array) {
 
 
  151    std::array<size_t, Count> m_array;
 
 
  176            usage = GL_DYNAMIC_DRAW;
 
  179            usage = GL_STATIC_DRAW;
 
  182            usage = GL_STREAM_DRAW;
 
 
  192            glDeleteBuffers(1, &
buffer);
 
 
  224    std::array<VertexAttrib, VertexAttributeCount> 
attrib;
 
 
  239    glBindBuffer(GL_ARRAY_BUFFER, 
buffer);
 
  245            glEnableVertexAttribArray(i);
 
 
  254            glDisableVertexAttribArray(i);
 
 
  263        glDeleteBuffers(1, &
buffer);
 
  277    const GLbitfield storage = GL_DYNAMIC_STORAGE_BIT;
 
  278    const GLbitfield access = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT;
 
  280    glBindBuffer(GL_ARRAY_BUFFER, 
buffer);
 
  281    glBufferStorage(GL_ARRAY_BUFFER, 
bufferSize, 
nullptr, storage | access);
 
  283    map = (uint8_t *)glMapBufferRange(GL_ARRAY_BUFFER, 0, 
bufferSize, access);
 
 
  292    while (!
fences.empty() && 
fences.front().nextEnd < end) {
 
  293        glDeleteSync(
fences.front().sync);
 
  297    Q_ASSERT(!
fences.empty());
 
  303        qCDebug(KWIN_OPENGL) << 
"Stalling on VBO fence";
 
  304        const GLenum ret = glClientWaitSync(fence.
sync, GL_SYNC_FLUSH_COMMANDS_BIT, 1000000000);
 
  306        if (ret == GL_TIMEOUT_EXPIRED || ret == GL_WAIT_FAILED) {
 
  307            qCCritical(KWIN_OPENGL) << 
"Wait failed";
 
  312    glDeleteSync(fence.
sync);
 
 
  337        if (
auto sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0)) {
 
 
  356    const size_t minSize = 32768; 
 
  357    const size_t alloc = 
usage != GL_STATIC_DRAW ? std::max(size, minSize) : size;
 
  359    glBufferData(GL_ARRAY_BUFFER, alloc, 
nullptr, 
usage);
 
 
  366    GLbitfield access = GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
 
  373            access |= GL_MAP_INVALIDATE_BUFFER_BIT;
 
  374            access ^= GL_MAP_UNSYNCHRONIZED_BIT;
 
  380    return glMapBufferRange(GL_ARRAY_BUFFER, 
nextOffset, size, access);
 
 
  392    GLvoid *ptr = 
map(size);
 
  396    memcpy(ptr, data, size);
 
 
  402    d->mappedSize = size;
 
  403    d->frameSize += size;
 
  406        return d->getIdleRange(size);
 
  409    glBindBuffer(GL_ARRAY_BUFFER, d->buffer);
 
  414        return (GLvoid *)d->mapNextFreeRange(size);
 
  420    if (
size_t(d->dataStore.size()) < size) {
 
  421        d->dataStore.resize(size);
 
  424    return (GLvoid *)d->dataStore.data();
 
  430        d->baseAddress = d->nextOffset;
 
  431        d->nextOffset += 
align(d->mappedSize, 8);
 
  439        glUnmapBuffer(GL_ARRAY_BUFFER);
 
  441        d->baseAddress = d->nextOffset;
 
  442        d->nextOffset += 
align(d->mappedSize, 8);
 
  445        if (preferBufferSubData) {
 
  446            if ((d->nextOffset + d->mappedSize) > d->bufferSize) {
 
  447                d->reallocateBuffer(d->mappedSize);
 
  451            glBufferSubData(GL_ARRAY_BUFFER, d->nextOffset, d->mappedSize, d->dataStore.constData());
 
  453            d->baseAddress = d->nextOffset;
 
  454            d->nextOffset += 
align(d->mappedSize, 8);
 
  456            glBufferData(GL_ARRAY_BUFFER, d->mappedSize, d->dataStore.data(), d->usage);
 
  461        if (d->usage == GL_STATIC_DRAW) {
 
  462            d->dataStore = QByteArray();
 
 
  471    d->vertexCount = count;
 
 
  476    d->enabledArrays.reset();
 
  477    for (
const auto &attrib : attribs) {
 
  478        Q_ASSERT(attrib.attributeIndex < d->attrib.size());
 
  479        d->attrib[attrib.attributeIndex].size = attrib.componentCount;
 
  480        d->attrib[attrib.attributeIndex].type = attrib.type;
 
  481        d->attrib[attrib.attributeIndex].offset = attrib.relativeOffset;
 
  482        d->enabledArrays[attrib.attributeIndex] = 
true;
 
  484    d->attribStride = stride;
 
 
  495    draw(region, primitiveMode, 0, d->vertexCount, hardwareClipping);
 
 
  514void GLVertexBuffer::draw(
const QRegion ®ion, GLenum primitiveMode, 
int first, 
int count, 
bool hardwareClipping)
 
  516    if (primitiveMode == GL_QUADS) {
 
  524        count = count * 6 / 4;
 
  526        if (!hardwareClipping) {
 
  527            glDrawElementsBaseVertex(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, 
nullptr, first);
 
  531            for (
const QRect &r : region) {
 
  532                glScissor(r.x(), current->
size().height() - (r.y() + r.height()), r.width(), r.height());
 
  533                glDrawElementsBaseVertex(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, 
nullptr, first);
 
  539    if (!hardwareClipping) {
 
  540        glDrawArrays(primitiveMode, first, count);
 
  544        for (
const QRect &r : region) {
 
  545            glScissor(r.x(), current->
size().height() - (r.y() + r.height()), r.width(), r.height());
 
  546            glDrawArrays(primitiveMode, first, count);
 
 
  563    if (!d->persistent) {
 
  568    if (d->frameSize > 0) {
 
  569        d->frameSizes.push(d->frameSize);
 
  574        if (d->frameSizes.average() > d->bufferSize / 2) {
 
  575            deleteAll(d->fences);
 
  576            glDeleteBuffers(1, &d->buffer);
 
  583            if (
auto sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0)) {
 
  586                    .nextEnd = intptr_t(d->nextOffset + d->bufferSize)});
 
 
  594    if (!d->persistent) {
 
  599    while (d->fences.size() > 1 && d->fences.front().signaled()) {
 
  601        glDeleteSync(fence.
sync);
 
  604        d->fences.pop_front();
 
 
  611        bool haveBaseVertex = 
hasGLExtension(QByteArrayLiteral(
"GL_OES_draw_elements_base_vertex"));
 
  613        bool haveMapBufferRange = 
hasGLExtension(QByteArrayLiteral(
"GL_EXT_map_buffer_range"));
 
  633        if (qgetenv(
"KWIN_PERSISTENT_VBO") != QByteArrayLiteral(
"0")) {
 
 
OpenGL framebuffer object.
static GLFramebuffer * currentFramebuffer()
void draw(GLenum primitiveMode, int first, int count)
static bool supportsIndexedQuads()
void setAttribLayout(std::span< const GLVertexAttrib > attribs, size_t stride)
void setData(const void *data, size_t sizeInBytes)
static GLVertexBuffer * streamingBuffer()
GLVertexBuffer(UsageHint hint)
void render(GLenum primitiveMode)
std::optional< std::span< T > > map(size_t count)
@ Static
No changes to data.
@ Stream
Data only used once for rendering, updated very frequently.
@ Dynamic
frequent changes, but used several times for rendering
void setVertexCount(int count)
static bool hasMapBufferRange
std::bitset< 32 > enabledArrays
static std::unique_ptr< IndexBuffer > s_indexBuffer
GLVertexBufferPrivate(GLVertexBuffer::UsageHint usageHint)
FrameSizesArray< 4 > frameSizes
static bool haveSyncFences
std::deque< BufferFence > fences
static std::unique_ptr< GLVertexBuffer > streamingBuffer
std::array< VertexAttrib, VertexAttributeCount > attrib
static bool haveBufferStorage
static bool supportsIndexedQuads
bool awaitFence(intptr_t offset)
void reallocatePersistentBuffer(size_t size)
GLvoid * mapNextFreeRange(size_t size)
GLvoid * getIdleRange(size_t size)
void reallocateBuffer(size_t size)
void accommodate(size_t count)
KWIN_EXPORT QRect infiniteRegion()
T align(T value, int bytes)
bool hasGLVersion(int major, int minor, int release)
bool hasGLExtension(const QByteArray &extension)