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)