GLUtil.hh 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  1. #ifndef GLUTIL_HH
  2. #define GLUTIL_HH
  3. // Check for availability of OpenGL.
  4. #include "components.hh"
  5. #if COMPONENT_GL
  6. // Include GLEW headers.
  7. #include <GL/glew.h>
  8. // Include OpenGL headers.
  9. #ifdef __APPLE__
  10. #include <OpenGL/gl.h>
  11. #else
  12. #include <GL/gl.h>
  13. #endif
  14. #include "MemBuffer.hh"
  15. #include "build-info.hh"
  16. #include <string>
  17. #include <cassert>
  18. namespace gl {
  19. // TODO this needs glu, but atm we don't link against glu (in windows)
  20. //void checkGLError(const std::string& prefix);
  21. // Dummy object, to be able to construct empty handler objects.
  22. struct Null {};
  23. /** Most basic/generic texture: only contains a texture ID.
  24. * Current implementation always assumes 2D textures.
  25. */
  26. class Texture
  27. {
  28. public:
  29. Texture(const Texture&) = delete;
  30. Texture& operator=(const Texture&) = delete;
  31. /** Allocate a openGL texture name and enable/disable interpolation. */
  32. explicit Texture(bool interpolation = false, bool wrap = false);
  33. /** Create null-handle (not yet allocate an openGL handle). */
  34. explicit Texture(Null) : textureId(0) {}
  35. /** Release openGL texture name. */
  36. ~Texture() { reset(); }
  37. /** Move constructor and assignment. */
  38. Texture(Texture&& other) noexcept
  39. : textureId(other.textureId)
  40. {
  41. other.textureId = 0; // 0 is not a valid openGL texture name
  42. }
  43. Texture& operator=(Texture&& other) noexcept {
  44. std::swap(textureId, other.textureId);
  45. return *this;
  46. }
  47. /** Allocate an openGL texture name. */
  48. void allocate();
  49. /** Release openGL texture name. */
  50. void reset();
  51. /** Returns the underlying openGL handler id.
  52. * 0 iff no openGL texture is allocated.
  53. */
  54. GLuint get() const { return textureId; }
  55. /** Makes this texture the active GL texture.
  56. * The other methods of this class and its subclasses will implicitly
  57. * bind the texture, so you only need this method to explicitly bind
  58. * this texture for use in GL function calls outside of this class.
  59. */
  60. void bind() {
  61. glBindTexture(GL_TEXTURE_2D, textureId);
  62. }
  63. /** Enable/disable bilinear interpolation for this texture. IOW selects
  64. * between GL_NEAREST or GL_LINEAR filtering.
  65. */
  66. void setInterpolation(bool interpolation);
  67. void setWrapMode(bool wrap);
  68. protected:
  69. GLuint textureId;
  70. friend class FrameBufferObject;
  71. };
  72. class ColorTexture : public Texture
  73. {
  74. public:
  75. /** Default constructor, zero-sized texture. */
  76. ColorTexture() = default;
  77. /** Create color texture with given size.
  78. * Initial content is undefined.
  79. */
  80. ColorTexture(GLsizei width, GLsizei height);
  81. void resize(GLsizei width, GLsizei height);
  82. GLsizei getWidth () const { return width; }
  83. GLsizei getHeight() const { return height; }
  84. private:
  85. GLsizei width = 0;
  86. GLsizei height = 0;
  87. };
  88. class FrameBufferObject
  89. {
  90. public:
  91. FrameBufferObject() = default;
  92. explicit FrameBufferObject(Texture& texture);
  93. FrameBufferObject(FrameBufferObject&& other) noexcept
  94. : bufferId(other.bufferId)
  95. {
  96. other.bufferId = 0;
  97. }
  98. FrameBufferObject& operator=(FrameBufferObject&& other) noexcept {
  99. std::swap(bufferId, other.bufferId);
  100. return *this;
  101. }
  102. ~FrameBufferObject();
  103. void push();
  104. void pop();
  105. private:
  106. GLuint bufferId = 0; // 0 is not a valid openGL name
  107. GLint previousId = 0;
  108. };
  109. /** Wrapper around a pixel buffer.
  110. * The pixel buffer will be allocated in VRAM if possible, in main RAM
  111. * otherwise.
  112. * The pixel type is templatized T.
  113. */
  114. template <typename T> class PixelBuffer
  115. {
  116. public:
  117. PixelBuffer();
  118. PixelBuffer(PixelBuffer&& other) noexcept;
  119. PixelBuffer& operator=(PixelBuffer&& other) noexcept;
  120. ~PixelBuffer();
  121. /** Sets the image for this buffer.
  122. * TODO: Actually, only image size for now;
  123. * later, if we need it, image data too.
  124. */
  125. void setImage(GLuint width, GLuint height);
  126. /** Bind this PixelBuffer. Must be called before the methods
  127. * getOffset() or mapWrite() are used. (Is a wrapper around
  128. * glBindBuffer).
  129. */
  130. void bind() const;
  131. /** Unbind this buffer.
  132. */
  133. void unbind() const;
  134. /** Gets a pointer relative to the start of this buffer.
  135. * You must not dereference this pointer, but you can pass it to
  136. * glTexImage etc when this buffer is bound as the source.
  137. * @pre This PixelBuffer must be bound (see bind()) before calling
  138. * this method.
  139. */
  140. T* getOffset(GLuint x, GLuint y);
  141. /** Maps the contents of this buffer into memory. The returned buffer
  142. * is write-only (reading could be very slow or even result in a
  143. * segfault).
  144. * @return Pointer through which you can write pixels to this buffer,
  145. * or 0 if the buffer could not be mapped.
  146. * @pre This PixelBuffer must be bound (see bind()) before calling
  147. * this method.
  148. */
  149. T* mapWrite();
  150. /** Unmaps the contents of this buffer.
  151. * After this call, you must no longer use the pointer returned by
  152. * mapWrite.
  153. */
  154. void unmap() const;
  155. private:
  156. /** Buffer for main RAM fallback (not allocated in the normal case).
  157. */
  158. openmsx::MemBuffer<T> allocated;
  159. /** Handle of the GL buffer, or 0 if no GL buffer is available.
  160. */
  161. GLuint bufferId;
  162. /** Number of pixels per line.
  163. */
  164. GLuint width = 0;
  165. /** Number of lines.
  166. */
  167. GLuint height = 0;
  168. };
  169. // class PixelBuffer
  170. template <typename T>
  171. PixelBuffer<T>::PixelBuffer()
  172. {
  173. glGenBuffers(1, &bufferId);
  174. }
  175. template <typename T>
  176. PixelBuffer<T>::PixelBuffer(PixelBuffer<T>&& other) noexcept
  177. : allocated(std::move(other.allocated))
  178. , bufferId(other.bufferId)
  179. , width(other.width)
  180. , height(other.height)
  181. {
  182. other.bufferId = 0;
  183. }
  184. template <typename T>
  185. PixelBuffer<T>& PixelBuffer<T>::operator=(PixelBuffer<T>&& other) noexcept
  186. {
  187. std::swap(allocated, other.allocated);
  188. std::swap(bufferId, other.bufferId);
  189. std::swap(width, other.width);
  190. std::swap(height, other.height);
  191. return *this;
  192. }
  193. template <typename T>
  194. PixelBuffer<T>::~PixelBuffer()
  195. {
  196. glDeleteBuffers(1, &bufferId); // ok to delete '0'
  197. }
  198. template <typename T>
  199. void PixelBuffer<T>::setImage(GLuint width_, GLuint height_)
  200. {
  201. width = width_;
  202. height = height_;
  203. if (bufferId != 0) {
  204. bind();
  205. // TODO make performance hint configurable?
  206. glBufferData(GL_PIXEL_UNPACK_BUFFER,
  207. width * height * 4,
  208. nullptr, // leave data undefined
  209. GL_STREAM_DRAW); // performance hint
  210. unbind();
  211. } else {
  212. allocated.resize(width * height);
  213. }
  214. }
  215. template <typename T>
  216. void PixelBuffer<T>::bind() const
  217. {
  218. if (bufferId != 0) {
  219. glBindBuffer(GL_PIXEL_UNPACK_BUFFER, bufferId);
  220. }
  221. }
  222. template <typename T>
  223. void PixelBuffer<T>::unbind() const
  224. {
  225. if (bufferId != 0) {
  226. glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
  227. }
  228. }
  229. template <typename T>
  230. T* PixelBuffer<T>::getOffset(GLuint x, GLuint y)
  231. {
  232. assert(x < width);
  233. assert(y < height);
  234. auto offset = x + size_t(width) * y;
  235. if (bufferId != 0) {
  236. return reinterpret_cast<T*>(offset * sizeof(T));
  237. } else {
  238. return &allocated[offset];
  239. }
  240. }
  241. template <typename T>
  242. T* PixelBuffer<T>::mapWrite()
  243. {
  244. if (bufferId != 0) {
  245. return reinterpret_cast<T*>(glMapBuffer(
  246. GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY));
  247. } else {
  248. return allocated.data();
  249. }
  250. }
  251. template <typename T>
  252. void PixelBuffer<T>::unmap() const
  253. {
  254. if (bufferId != 0) {
  255. glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
  256. }
  257. }
  258. /** Wrapper around an OpenGL shader: a program executed on the GPU.
  259. * This class is a base class for vertex and fragment shaders.
  260. */
  261. class Shader
  262. {
  263. public:
  264. /** Returns true iff this shader is loaded and compiled without errors.
  265. */
  266. bool isOK() const;
  267. protected:
  268. /** Instantiates a shader.
  269. * @param type The shader type: GL_VERTEX_SHADER or GL_FRAGMENT_SHADER.
  270. * @param filename The GLSL source code for the shader.
  271. */
  272. Shader(GLenum type, const std::string& filename);
  273. Shader(GLenum type, const std::string& header,
  274. const std::string& filename);
  275. ~Shader();
  276. private:
  277. void init(GLenum type, const std::string& header,
  278. const std::string& filename);
  279. friend class ShaderProgram;
  280. GLuint handle;
  281. };
  282. /** Wrapper around an OpenGL vertex shader:
  283. * a program executed on the GPU that computes per-vertex stuff.
  284. */
  285. class VertexShader : public Shader
  286. {
  287. public:
  288. /** Instantiates a vertex shader.
  289. * @param filename The GLSL source code for the shader.
  290. */
  291. explicit VertexShader(const std::string& filename);
  292. VertexShader(const std::string& header, const std::string& filename);
  293. };
  294. /** Wrapper around an OpenGL fragment shader:
  295. * a program executed on the GPU that computes the colors of pixels.
  296. */
  297. class FragmentShader : public Shader
  298. {
  299. public:
  300. /** Instantiates a fragment shader.
  301. * @param filename The GLSL source code for the shader.
  302. */
  303. explicit FragmentShader(const std::string& filename);
  304. FragmentShader(const std::string& header, const std::string& filename);
  305. };
  306. /** Wrapper around an OpenGL program:
  307. * a collection of vertex and fragment shaders.
  308. */
  309. class ShaderProgram
  310. {
  311. public:
  312. ShaderProgram(const ShaderProgram&) = delete;
  313. ShaderProgram& operator=(const ShaderProgram&) = delete;
  314. /** Create handler and allocate underlying openGL object. */
  315. ShaderProgram() { allocate(); }
  316. /** Create null handler (don't yet allocate a openGL object). */
  317. explicit ShaderProgram(Null) : handle(0) {}
  318. /** Destroy handler object (release the underlying openGL object). */
  319. ~ShaderProgram() { reset(); }
  320. /** Allocate a shader program handle. */
  321. void allocate();
  322. /** Release the shader program handle. */
  323. void reset();
  324. /** Returns the underlying openGL handler id.
  325. * 0 iff no openGL program is allocated.
  326. */
  327. GLuint get() const { return handle; }
  328. /** Returns true iff this program was linked without errors.
  329. * Note that this will certainly return false until link() is called.
  330. */
  331. bool isOK() const;
  332. /** Adds a given shader to this program.
  333. */
  334. void attach(const Shader& shader);
  335. /** Links all attached shaders together into one program.
  336. * This should be done before activating the program.
  337. */
  338. void link();
  339. /** Bind the given name for a vertex shader attribute to the given
  340. * location.
  341. */
  342. void bindAttribLocation(unsigned index, const char* name);
  343. /** Gets a reference to a uniform variable declared in the shader source.
  344. * Note that you have to activate this program before you can change
  345. * the uniform variable's value.
  346. */
  347. GLint getUniformLocation(const char* name) const;
  348. /** Makes this program the active shader program.
  349. * This requires that the program is already linked.
  350. */
  351. void activate() const;
  352. void validate() const;
  353. private:
  354. GLuint handle;
  355. };
  356. class BufferObject
  357. {
  358. public:
  359. BufferObject();
  360. ~BufferObject();
  361. BufferObject(BufferObject&& other) noexcept
  362. : bufferId(other.bufferId)
  363. {
  364. other.bufferId = 0;
  365. }
  366. BufferObject& operator=(BufferObject&& other) noexcept {
  367. std::swap(bufferId, other.bufferId);
  368. return *this;
  369. }
  370. GLuint get() const { return bufferId; }
  371. private:
  372. GLuint bufferId;
  373. };
  374. class VertexArray
  375. {
  376. public:
  377. VertexArray();
  378. ~VertexArray();
  379. VertexArray(VertexArray&& other) noexcept
  380. : bufferId(other.bufferId)
  381. {
  382. other.bufferId = 0;
  383. }
  384. VertexArray& operator=(VertexArray&& other) noexcept {
  385. std::swap(bufferId, other.bufferId);
  386. return *this;
  387. }
  388. /** Bind this VertexArray. Must be called before glDraw*() and
  389. * glVertexAttribPointer() are used.
  390. */
  391. void bind() const { glBindVertexArray(bufferId); }
  392. /** Unbind this VertexArray.
  393. */
  394. void unbind() const { glBindVertexArray(0); }
  395. GLuint get() const { return bufferId; }
  396. private:
  397. GLuint bufferId;
  398. };
  399. } // namespace gl
  400. #endif // COMPONENT_GL
  401. #endif // GLUTIL_HH