File indexing completed on 2024-05-19 05:31:56

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2006-2007 Rivo Laks <rivolaks@hot.ee>
0006     SPDX-FileCopyrightText: 2010, 2011 Martin Gräßlin <mgraesslin@kde.org>
0007     SPDX-FileCopyrightText: 2023 Xaver Hugl <xaver.hugl@kde.org>
0008 
0009     SPDX-License-Identifier: GPL-2.0-or-later
0010 */
0011 #pragma once
0012 #include "kwin_export.h"
0013 
0014 #include <QColor>
0015 #include <QRegion>
0016 #include <QVector2D>
0017 
0018 #include <epoxy/gl.h>
0019 #include <optional>
0020 #include <ranges>
0021 #include <span>
0022 
0023 namespace KWin
0024 {
0025 
0026 enum VertexAttributeType {
0027     VA_Position = 0,
0028     VA_TexCoord = 1,
0029     VertexAttributeCount = 2,
0030 };
0031 
0032 struct GLVertex2D
0033 {
0034     QVector2D position;
0035     QVector2D texcoord;
0036 };
0037 
0038 struct GLVertex3D
0039 {
0040     QVector3D position;
0041     QVector2D texcoord;
0042 };
0043 
0044 /**
0045  * Describes the format of a vertex attribute stored in a buffer object.
0046  *
0047  * The attribute format consists of the attribute index, the number of
0048  * vector components, the data type, and the offset of the first element
0049  * relative to the start of the vertex data.
0050  */
0051 struct GLVertexAttrib
0052 {
0053     size_t attributeIndex;
0054     size_t componentCount;
0055     GLenum type; /** The type (e.g. GL_FLOAT) */
0056     size_t relativeOffset; /** The relative offset of the attribute */
0057 };
0058 
0059 class GLVertexBufferPrivate;
0060 
0061 /**
0062  * @short Vertex Buffer Object
0063  *
0064  * This is a short helper class to use vertex buffer objects (VBO). A VBO can be used to buffer
0065  * vertex data and to store them on graphics memory.
0066  *
0067  * @author Martin Gräßlin <mgraesslin@kde.org>
0068  * @since 4.6
0069  */
0070 class KWIN_EXPORT GLVertexBuffer
0071 {
0072 public:
0073     /**
0074      * Enum to define how often the vertex data in the buffer object changes.
0075      */
0076     enum UsageHint {
0077         Dynamic, ///< frequent changes, but used several times for rendering
0078         Static, ///< No changes to data
0079         Stream ///< Data only used once for rendering, updated very frequently
0080     };
0081 
0082     explicit GLVertexBuffer(UsageHint hint);
0083     ~GLVertexBuffer();
0084 
0085     /**
0086      * Specifies how interleaved vertex attributes are laid out in
0087      * the buffer object.
0088      *
0089      * Note that the attributes and the stride should be 32 bit aligned
0090      * or a performance penalty may be incurred.
0091      *
0092      * For some hardware the optimal stride is a multiple of 32 bytes.
0093      *
0094      * Example:
0095      *
0096      *     struct Vertex {
0097      *         QVector3D position;
0098      *         QVector2D texcoord;
0099      *     };
0100      *
0101      *     const std::array attribs = {
0102      *         GLVertexAttrib{ VA_Position, 3, GL_FLOAT, offsetof(Vertex, position) },
0103      *         GLVertexAttrib{ VA_TexCoord, 2, GL_FLOAT, offsetof(Vertex, texcoord) },
0104      *     };
0105      *
0106      *     Vertex vertices[6];
0107      *     vbo->setAttribLayout(std::span(attribs), sizeof(Vertex));
0108      *     vbo->setData(vertices, sizeof(vertices));
0109      */
0110     void setAttribLayout(std::span<const GLVertexAttrib> attribs, size_t stride);
0111 
0112     /**
0113      * Uploads data into the buffer object's data store.
0114      */
0115     void setData(const void *data, size_t sizeInBytes);
0116 
0117     /**
0118      * Sets the number of vertices that will be drawn by the render() method.
0119      */
0120     void setVertexCount(int count);
0121 
0122     // clang-format off
0123     template<std::ranges::contiguous_range T>
0124         requires std::is_same<std::ranges::range_value_t<T>, GLVertex2D>::value
0125     void setVertices(const T &range)
0126     {
0127         setData(range.data(), range.size() * sizeof(GLVertex2D));
0128         setVertexCount(range.size());
0129         setAttribLayout(std::span(GLVertex2DLayout), sizeof(GLVertex2D));
0130     }
0131 
0132     template<std::ranges::contiguous_range T>
0133         requires std::is_same<std::ranges::range_value_t<T>, GLVertex3D>::value
0134     void setVertices(const T &range)
0135     {
0136         setData(range.data(), range.size() * sizeof(GLVertex3D));
0137         setVertexCount(range.size());
0138         setAttribLayout(std::span(GLVertex3DLayout), sizeof(GLVertex3D));
0139     }
0140 
0141     template<std::ranges::contiguous_range T>
0142         requires std::is_same<std::ranges::range_value_t<T>, QVector2D>::value
0143     void setVertices(const T &range)
0144     {
0145         setData(range.data(), range.size() * sizeof(QVector2D));
0146         setVertexCount(range.size());
0147         static constexpr GLVertexAttrib layout{
0148             .attributeIndex = VA_Position,
0149             .componentCount = 2,
0150             .type = GL_FLOAT,
0151             .relativeOffset = 0,
0152         };
0153         setAttribLayout(std::span(&layout, 1), sizeof(QVector2D));
0154     }
0155     // clang-format on
0156 
0157     /**
0158      * Maps an unused range of the data store into the client's address space.
0159      *
0160      * The data store will be reallocated if it is smaller than the given size.
0161      *
0162      * The buffer object is mapped for writing, not reading. Attempts to read from
0163      * the mapped buffer range may result in system errors, including program
0164      * termination. The data in the mapped region is undefined until it has been
0165      * written to. If subsequent GL calls access unwritten memory, the results are
0166      * undefined and system errors, including program termination, may occur.
0167      *
0168      * No GL calls that access the buffer object must be made while the buffer
0169      * object is mapped. The returned pointer must not be passed as a parameter
0170      * value to any GL function.
0171      *
0172      * It is assumed that the GL_ARRAY_BUFFER_BINDING will not be changed while
0173      * the buffer object is mapped.
0174      */
0175     template<typename T>
0176     std::optional<std::span<T>> map(size_t count)
0177     {
0178         if (const auto m = map(sizeof(T) * count)) {
0179             return std::span(reinterpret_cast<T *>(m), count);
0180         } else {
0181             return std::nullopt;
0182         }
0183     }
0184 
0185     /**
0186      * Flushes the mapped buffer range and unmaps the buffer.
0187      */
0188     void unmap();
0189 
0190     /**
0191      * Binds the vertex arrays to the context.
0192      */
0193     void bindArrays();
0194 
0195     /**
0196      * Disables the vertex arrays.
0197      */
0198     void unbindArrays();
0199 
0200     /**
0201      * Draws count vertices beginning with first.
0202      */
0203     void draw(GLenum primitiveMode, int first, int count);
0204 
0205     /**
0206      * Draws count vertices beginning with first.
0207      */
0208     void draw(const QRegion &region, GLenum primitiveMode, int first, int count, bool hardwareClipping = false);
0209 
0210     /**
0211      * Renders the vertex data in given @a primitiveMode.
0212      * Please refer to OpenGL documentation of glDrawArrays or glDrawElements for allowed
0213      * values for @a primitiveMode. Best is to use GL_TRIANGLES or similar to be future
0214      * compatible.
0215      */
0216     void render(GLenum primitiveMode);
0217     /**
0218      * Same as above restricting painting to @a region if @a hardwareClipping is true.
0219      * It's within the caller's responsibility to enable GL_SCISSOR_TEST.
0220      */
0221     void render(const QRegion &region, GLenum primitiveMode, bool hardwareClipping = false);
0222 
0223     /**
0224      * Resets the instance to default values.
0225      * Useful for shared buffers.
0226      * @since 4.7
0227      */
0228     void reset();
0229 
0230     /**
0231      * Notifies the vertex buffer that we are done painting the frame.
0232      *
0233      * @internal
0234      */
0235     void endOfFrame();
0236 
0237     /**
0238      * Notifies the vertex buffer that we are about to paint a frame.
0239      *
0240      * @internal
0241      */
0242     void beginFrame();
0243 
0244     /**
0245      * @internal
0246      */
0247     static void initStatic();
0248 
0249     /**
0250      * @internal
0251      */
0252     static void cleanup();
0253 
0254     /**
0255      * Returns true if indexed quad mode is supported, and false otherwise.
0256      */
0257     static bool supportsIndexedQuads();
0258 
0259     /**
0260      * @return A shared VBO for streaming data
0261      * @since 4.7
0262      */
0263     static GLVertexBuffer *streamingBuffer();
0264 
0265     static constexpr std::array GLVertex2DLayout{
0266         GLVertexAttrib{
0267             .attributeIndex = VA_Position,
0268             .componentCount = 2,
0269             .type = GL_FLOAT,
0270             .relativeOffset = offsetof(GLVertex2D, position),
0271         },
0272         GLVertexAttrib{
0273             .attributeIndex = VA_TexCoord,
0274             .componentCount = 2,
0275             .type = GL_FLOAT,
0276             .relativeOffset = offsetof(GLVertex2D, texcoord),
0277         },
0278     };
0279     static constexpr std::array GLVertex3DLayout{
0280         GLVertexAttrib{
0281             .attributeIndex = VA_Position,
0282             .componentCount = 3,
0283             .type = GL_FLOAT,
0284             .relativeOffset = offsetof(GLVertex3D, position),
0285         },
0286         GLVertexAttrib{
0287             .attributeIndex = VA_TexCoord,
0288             .componentCount = 2,
0289             .type = GL_FLOAT,
0290             .relativeOffset = offsetof(GLVertex3D, texcoord),
0291         },
0292     };
0293 
0294 private:
0295     GLvoid *map(size_t size);
0296 
0297     const std::unique_ptr<GLVertexBufferPrivate> d;
0298 };
0299 
0300 }