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 ®ion, 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 ®ion, 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 }