Buffer.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. /**
  2. * Copyright (c) 2006-2021 LOVE Development Team
  3. *
  4. * This software is provided 'as-is', without any express or implied
  5. * warranty. In no event will the authors be held liable for any damages
  6. * arising from the use of this software.
  7. *
  8. * Permission is granted to anyone to use this software for any purpose,
  9. * including commercial applications, and to alter it and redistribute it
  10. * freely, subject to the following restrictions:
  11. *
  12. * 1. The origin of this software must not be misrepresented; you must not
  13. * claim that you wrote the original software. If you use this software
  14. * in a product, an acknowledgment in the product documentation would be
  15. * appreciated but is not required.
  16. * 2. Altered source versions must be plainly marked as such, and must not be
  17. * misrepresented as being the original software.
  18. * 3. This notice may not be removed or altered from any source distribution.
  19. **/
  20. #include "Buffer.h"
  21. #include "Graphics.h"
  22. #include "common/memory.h"
  23. namespace love
  24. {
  25. namespace graphics
  26. {
  27. love::Type Buffer::type("GraphicsBuffer", &Object::type);
  28. Buffer::Buffer(Graphics *gfx, const Settings &settings, const std::vector<DataDeclaration> &bufferformat, size_t size, size_t arraylength)
  29. : arrayLength(0)
  30. , arrayStride(0)
  31. , size(size)
  32. , usageFlags(settings.usageFlags)
  33. , dataUsage(settings.dataUsage)
  34. , mapped(false)
  35. {
  36. if (size == 0 && arraylength == 0)
  37. throw love::Exception("Size or array length must be specified.");
  38. if (bufferformat.size() == 0)
  39. throw love::Exception("Data format must contain values.");
  40. const auto &caps = gfx->getCapabilities();
  41. bool supportsGLSL3 = caps.features[Graphics::FEATURE_GLSL3];
  42. bool indexbuffer = settings.usageFlags & BUFFERUSAGEFLAG_INDEX;
  43. bool vertexbuffer = settings.usageFlags & BUFFERUSAGEFLAG_VERTEX;
  44. bool texelbuffer = settings.usageFlags & BUFFERUSAGEFLAG_TEXEL;
  45. bool storagebuffer = settings.usageFlags & BUFFERUSAGEFLAG_SHADER_STORAGE;
  46. bool copydest = settings.usageFlags & BUFFERUSAGEFLAG_COPY_DEST;
  47. if (!indexbuffer && !vertexbuffer && !texelbuffer && !storagebuffer)
  48. throw love::Exception("Buffer must be created with at least one buffer type (index, vertex, texel, or shaderstorage).");
  49. if (texelbuffer && !caps.features[Graphics::FEATURE_TEXEL_BUFFER])
  50. throw love::Exception("Texel buffers are not supported on this system.");
  51. if (storagebuffer && !caps.features[Graphics::FEATURE_GLSL4])
  52. throw love::Exception("Shader Storage buffers are not supported on this system (GLSL 4 support is necessary.)");
  53. if (copydest && dataUsage == BUFFERDATAUSAGE_STREAM)
  54. throw love::Exception("Buffers created with 'stream' data usage cannot be used as a copy destination.");
  55. size_t offset = 0;
  56. size_t stride = 0;
  57. size_t structurealignment = 1;
  58. for (const DataDeclaration &decl : bufferformat)
  59. {
  60. DataMember member(decl);
  61. DataFormat format = member.decl.format;
  62. const DataFormatInfo &info = member.info;
  63. if (indexbuffer)
  64. {
  65. if (format != DATAFORMAT_UINT16 && format != DATAFORMAT_UINT32)
  66. throw love::Exception("Index buffers only support uint16 and uint32 data types.");
  67. if (bufferformat.size() > 1)
  68. throw love::Exception("Index buffers only support a single value per element.");
  69. if (decl.arrayLength > 0)
  70. throw love::Exception("Arrays are not supported in index buffers.");
  71. }
  72. if (vertexbuffer)
  73. {
  74. if (decl.arrayLength > 0)
  75. throw love::Exception("Arrays are not supported in vertex buffers.");
  76. if (info.isMatrix)
  77. throw love::Exception("Matrix types are not supported in vertex buffers.");
  78. if (info.baseType == DATA_BASETYPE_BOOL)
  79. throw love::Exception("Bool types are not supported in vertex buffers.");
  80. if ((info.baseType == DATA_BASETYPE_INT || info.baseType == DATA_BASETYPE_UINT) && !supportsGLSL3)
  81. throw love::Exception("Integer vertex attribute data types require GLSL 3 support.");
  82. if (decl.name.empty())
  83. throw love::Exception("Vertex buffer attributes must have a name.");
  84. }
  85. if (texelbuffer)
  86. {
  87. if (format != bufferformat[0].format)
  88. throw love::Exception("All values in a texel buffer must have the same format.");
  89. if (decl.arrayLength > 0)
  90. throw love::Exception("Arrays are not supported in texel buffers.");
  91. if (info.isMatrix)
  92. throw love::Exception("Matrix types are not supported in texel buffers.");
  93. if (info.baseType == DATA_BASETYPE_BOOL)
  94. throw love::Exception("Bool types are not supported in texel buffers.");
  95. if (info.components == 3)
  96. throw love::Exception("3-component formats are not supported in texel buffers.");
  97. if (info.baseType == DATA_BASETYPE_SNORM)
  98. throw love::Exception("Signed normalized formats are not supported in texel buffers.");
  99. }
  100. size_t memberoffset = offset;
  101. size_t membersize = member.info.size;
  102. // Storage buffers are always treated as being an array of a structure.
  103. // The structure's contents are the buffer format declaration.
  104. if (storagebuffer)
  105. {
  106. // TODO: We can support these.
  107. if (decl.arrayLength > 0)
  108. throw love::Exception("Arrays are not currently supported in shader storage buffers.");
  109. if (info.baseType == DATA_BASETYPE_BOOL)
  110. throw love::Exception("Bool types are not supported in shader storage buffers.");
  111. if (info.baseType == DATA_BASETYPE_UNORM || info.baseType == DATA_BASETYPE_SNORM)
  112. throw love::Exception("Normalized formats are not supported in shader storage buffers.");
  113. size_t alignment = 1;
  114. // GLSL's std430 packing rules. We also assume all matrices are
  115. // column-major.
  116. // https://www.khronos.org/registry/OpenGL/specs/gl/glspec46.core.pdf
  117. // "If the member is a column-major matrix with C columns and R rows,
  118. // the matrix is stored identically to an array of C column vectors
  119. // with R components each".
  120. // "If the member is a three-component vector with components
  121. // consuming N basic machine units, the base alignment is 4N."
  122. int c = info.isMatrix ? info.matrixRows : info.components;
  123. alignment = c == 3 ? 4 * info.componentSize : c * info.componentSize;
  124. // std430 will effectively turn a floatmat3x3 into a floatmat4x3
  125. // because of its vec3 padding rules. For now we'd rather not
  126. // support those formats at all, because it's not easy for users to
  127. // deal with.
  128. if (alignment != c * info.componentSize && (decl.arrayLength > 0 || info.isMatrix))
  129. {
  130. const char *fstr = "unknown";
  131. getConstant(decl.format, fstr);
  132. throw love::Exception("Data format %s%s is not currently supported in shader storage buffers.", fstr, decl.arrayLength > 0 ? " array" : "");
  133. }
  134. // "If the member is a structure, the base alignment of the structure
  135. // is N, where N is the largest base alignment value of any of its
  136. // members"
  137. structurealignment = std::max(structurealignment, alignment);
  138. memberoffset = alignUp(memberoffset, alignment);
  139. if (memberoffset != offset && (indexbuffer || vertexbuffer || texelbuffer))
  140. throw love::Exception("Cannot create Buffer:\nInternal alignment of member '%s' is preventing Buffer from being created as both a shader storage buffer and other buffer types\nMember byte offset needed for shader storage buffer: %d\nMember byte offset needed for other buffer types: %d",
  141. member.decl.name.c_str(), memberoffset, offset);
  142. }
  143. member.offset = memberoffset;
  144. member.size = membersize;
  145. offset = member.offset + member.size;
  146. dataMembers.push_back(member);
  147. }
  148. stride = alignUp(offset, structurealignment);
  149. if (storagebuffer && (indexbuffer || vertexbuffer || texelbuffer))
  150. {
  151. if (stride != offset)
  152. throw love::Exception("Cannot create Buffer:\nBuffer used as a shader storage buffer would have a different number of bytes per array element (%d) than when used as other buffer types (%d)",
  153. stride, offset);
  154. }
  155. if (storagebuffer && stride > SHADER_STORAGE_BUFFER_MAX_STRIDE)
  156. throw love::Exception("Shader storage buffers cannot have more than %d bytes within each array element.", SHADER_STORAGE_BUFFER_MAX_STRIDE);
  157. if (size != 0)
  158. {
  159. size_t remainder = size % stride;
  160. if (remainder > 0)
  161. size += stride - remainder;
  162. arraylength = size / stride;
  163. }
  164. else
  165. {
  166. size = arraylength * stride;
  167. }
  168. this->arrayStride = stride;
  169. this->arrayLength = arraylength;
  170. this->size = size;
  171. if (texelbuffer && arraylength * dataMembers.size() > caps.limits[Graphics::LIMIT_TEXEL_BUFFER_SIZE])
  172. throw love::Exception("Cannot create texel buffer: total number of values in the buffer (%d * %d) is too large for this system (maximum %d).",
  173. (int) dataMembers.size(), (int) arraylength, caps.limits[Graphics::LIMIT_TEXEL_BUFFER_SIZE]);
  174. }
  175. Buffer::~Buffer()
  176. {
  177. }
  178. int Buffer::getDataMemberIndex(const std::string &name) const
  179. {
  180. for (size_t i = 0; i < dataMembers.size(); i++)
  181. {
  182. if (dataMembers[i].decl.name == name)
  183. return (int) i;
  184. }
  185. return -1;
  186. }
  187. std::vector<Buffer::DataDeclaration> Buffer::getCommonFormatDeclaration(CommonFormat format)
  188. {
  189. switch (format)
  190. {
  191. case CommonFormat::NONE:
  192. return {};
  193. case CommonFormat::XYf:
  194. return {
  195. { getConstant(ATTRIB_POS), DATAFORMAT_FLOAT_VEC2 }
  196. };
  197. case CommonFormat::XYZf:
  198. return {
  199. { getConstant(ATTRIB_POS), DATAFORMAT_FLOAT_VEC3 }
  200. };
  201. case CommonFormat::RGBAub:
  202. return {
  203. { getConstant(ATTRIB_COLOR), DATAFORMAT_UNORM8_VEC4 }
  204. };
  205. case CommonFormat::STf_RGBAub:
  206. return {
  207. { getConstant(ATTRIB_TEXCOORD), DATAFORMAT_FLOAT_VEC2 },
  208. { getConstant(ATTRIB_COLOR), DATAFORMAT_UNORM8_VEC4 },
  209. };
  210. case CommonFormat::STPf_RGBAub:
  211. return {
  212. { getConstant(ATTRIB_TEXCOORD), DATAFORMAT_FLOAT_VEC3 },
  213. { getConstant(ATTRIB_COLOR), DATAFORMAT_UNORM8_VEC4 },
  214. };
  215. case CommonFormat::XYf_STf:
  216. return {
  217. { getConstant(ATTRIB_POS), DATAFORMAT_FLOAT_VEC2 },
  218. { getConstant(ATTRIB_TEXCOORD), DATAFORMAT_FLOAT_VEC2 },
  219. };
  220. case CommonFormat::XYf_STPf:
  221. return {
  222. { getConstant(ATTRIB_POS), DATAFORMAT_FLOAT_VEC2 },
  223. { getConstant(ATTRIB_TEXCOORD), DATAFORMAT_FLOAT_VEC3 },
  224. };
  225. case CommonFormat::XYf_STf_RGBAub:
  226. return {
  227. { getConstant(ATTRIB_POS), DATAFORMAT_FLOAT_VEC2 },
  228. { getConstant(ATTRIB_TEXCOORD), DATAFORMAT_FLOAT_VEC2 },
  229. { getConstant(ATTRIB_COLOR), DATAFORMAT_UNORM8_VEC4 },
  230. };
  231. case CommonFormat::XYf_STus_RGBAub:
  232. return {
  233. { getConstant(ATTRIB_POS), DATAFORMAT_FLOAT_VEC2 },
  234. { getConstant(ATTRIB_TEXCOORD), DATAFORMAT_UNORM16_VEC2 },
  235. { getConstant(ATTRIB_COLOR), DATAFORMAT_UNORM8_VEC4 },
  236. };
  237. case CommonFormat::XYf_STPf_RGBAub:
  238. return {
  239. { getConstant(ATTRIB_POS), DATAFORMAT_FLOAT_VEC2 },
  240. { getConstant(ATTRIB_TEXCOORD), DATAFORMAT_FLOAT_VEC2 },
  241. { getConstant(ATTRIB_COLOR), DATAFORMAT_UNORM8_VEC4 },
  242. };
  243. }
  244. return {};
  245. }
  246. } // graphics
  247. } // love