1 //
2 // Copyright 2016 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // gl_raii:
7 //   Helper methods for containing GL objects like buffers and textures.
8 
9 #ifndef ANGLE_TESTS_GL_RAII_H_
10 #define ANGLE_TESTS_GL_RAII_H_
11 
12 #include <functional>
13 
14 #include "util/shader_utils.h"
15 
16 namespace angle
17 {
18 
19 // This is a bit of hack to work around a bug in MSVS intellisense, and make it very easy to
20 // use the correct function pointer type without worrying about the various definitions of
21 // GL_APICALL.
22 using GLGen    = decltype(glGenBuffers);
23 using GLDelete = decltype(glDeleteBuffers);
24 
25 class GLWrapper : angle::NonCopyable
26 {
27   public:
GLWrapper(GLGen * genFunc,GLDelete * deleteFunc)28     GLWrapper(GLGen *genFunc, GLDelete *deleteFunc) : mGenFunc(genFunc), mDeleteFunc(deleteFunc) {}
~GLWrapper()29     ~GLWrapper()
30     {
31         if (mHandle)
32         {
33             (*mDeleteFunc)(1, &mHandle);
34         }
35     }
36 
37     // The move-constructor and move-assignment operators are necessary so that the data within a
38     // GLWrapper object can be relocated.
GLWrapper(GLWrapper && rht)39     GLWrapper(GLWrapper &&rht)
40         : mGenFunc(rht.mGenFunc), mDeleteFunc(rht.mDeleteFunc), mHandle(rht.mHandle)
41     {
42         rht.mHandle = 0u;
43     }
44     GLWrapper &operator=(GLWrapper &&rht)
45     {
46         if (this != &rht)
47         {
48             mGenFunc    = rht.mGenFunc;
49             mDeleteFunc = rht.mDeleteFunc;
50             std::swap(mHandle, rht.mHandle);
51         }
52         return *this;
53     }
54 
reset()55     void reset()
56     {
57         if (mHandle != 0u)
58         {
59             (*mDeleteFunc)(1, &mHandle);
60             mHandle = 0u;
61         }
62     }
63 
get()64     GLuint get()
65     {
66         if (!mHandle)
67         {
68             (*mGenFunc)(1, &mHandle);
69         }
70         return mHandle;
71     }
72 
GLuint()73     operator GLuint() { return get(); }
74 
75   private:
76     GLGen *mGenFunc;
77     GLDelete *mDeleteFunc;
78     GLuint mHandle = 0u;
79 };
80 
81 class GLVertexArray : public GLWrapper
82 {
83   public:
GLVertexArray()84     GLVertexArray() : GLWrapper(&glGenVertexArrays, &glDeleteVertexArrays) {}
85 };
86 class GLBuffer : public GLWrapper
87 {
88   public:
GLBuffer()89     GLBuffer() : GLWrapper(&glGenBuffers, &glDeleteBuffers) {}
90 };
91 class GLTexture : public GLWrapper
92 {
93   public:
GLTexture()94     GLTexture() : GLWrapper(&glGenTextures, &glDeleteTextures) {}
95 };
96 class GLFramebuffer : public GLWrapper
97 {
98   public:
GLFramebuffer()99     GLFramebuffer() : GLWrapper(&glGenFramebuffers, &glDeleteFramebuffers) {}
100 };
101 class GLMemoryObject : public GLWrapper
102 {
103   public:
GLMemoryObject()104     GLMemoryObject() : GLWrapper(&glCreateMemoryObjectsEXT, &glDeleteMemoryObjectsEXT) {}
105 };
106 class GLRenderbuffer : public GLWrapper
107 {
108   public:
GLRenderbuffer()109     GLRenderbuffer() : GLWrapper(&glGenRenderbuffers, &glDeleteRenderbuffers) {}
110 };
111 class GLSampler : public GLWrapper
112 {
113   public:
GLSampler()114     GLSampler() : GLWrapper(&glGenSamplers, &glDeleteSamplers) {}
115 };
116 class GLSemaphore : public GLWrapper
117 {
118   public:
GLSemaphore()119     GLSemaphore() : GLWrapper(&glGenSemaphoresEXT, &glDeleteSemaphoresEXT) {}
120 };
121 class GLTransformFeedback : public GLWrapper
122 {
123   public:
GLTransformFeedback()124     GLTransformFeedback() : GLWrapper(&glGenTransformFeedbacks, &glDeleteTransformFeedbacks) {}
125 };
126 class GLProgramPipeline : public GLWrapper
127 {
128   public:
GLProgramPipeline()129     GLProgramPipeline() : GLWrapper(&glGenProgramPipelines, &glDeleteProgramPipelines) {}
130 };
131 class GLQueryEXT : public GLWrapper
132 {
133   public:
GLQueryEXT()134     GLQueryEXT() : GLWrapper(&glGenQueriesEXT, &glDeleteQueriesEXT) {}
135 };
136 using GLQuery = GLQueryEXT;
137 
138 class GLShader : angle::NonCopyable
139 {
140   public:
141     GLShader() = delete;
GLShader(GLenum shaderType)142     explicit GLShader(GLenum shaderType) { mHandle = glCreateShader(shaderType); }
143 
~GLShader()144     ~GLShader() { glDeleteShader(mHandle); }
145 
get()146     GLuint get() { return mHandle; }
147 
GLuint()148     operator GLuint() { return get(); }
149 
reset()150     void reset()
151     {
152         if (mHandle)
153         {
154             glDeleteShader(mHandle);
155             mHandle = 0;
156         }
157     }
158 
159   private:
160     GLuint mHandle;
161 };
162 
163 // Prefer ANGLE_GL_PROGRAM for local variables.
164 class GLProgram
165 {
166   public:
GLProgram()167     GLProgram() : mHandle(0) {}
168 
~GLProgram()169     ~GLProgram() { reset(); }
170 
makeEmpty()171     void makeEmpty() { mHandle = glCreateProgram(); }
172 
makeCompute(const char * computeShader)173     void makeCompute(const char *computeShader) { mHandle = CompileComputeProgram(computeShader); }
174 
makeRaster(const char * vertexShader,const char * fragmentShader)175     void makeRaster(const char *vertexShader, const char *fragmentShader)
176     {
177         mHandle = CompileProgram(vertexShader, fragmentShader);
178     }
179 
makeRaster(const char * vertexShader,const char * geometryShader,const char * fragmentShader)180     void makeRaster(const char *vertexShader,
181                     const char *geometryShader,
182                     const char *fragmentShader)
183     {
184         mHandle = CompileProgramWithGS(vertexShader, geometryShader, fragmentShader);
185     }
186 
makeRaster(const char * vertexShader,const char * tessControlShader,const char * tessEvaluateShader,const char * fragmentShader)187     void makeRaster(const char *vertexShader,
188                     const char *tessControlShader,
189                     const char *tessEvaluateShader,
190                     const char *fragmentShader)
191     {
192         mHandle = CompileProgramWithTESS(vertexShader, tessControlShader, tessEvaluateShader,
193                                          fragmentShader);
194     }
195 
makeRasterWithTransformFeedback(const char * vertexShader,const char * fragmentShader,const std::vector<std::string> & tfVaryings,GLenum bufferMode)196     void makeRasterWithTransformFeedback(const char *vertexShader,
197                                          const char *fragmentShader,
198                                          const std::vector<std::string> &tfVaryings,
199                                          GLenum bufferMode)
200     {
201         mHandle = CompileProgramWithTransformFeedback(vertexShader, fragmentShader, tfVaryings,
202                                                       bufferMode);
203     }
204 
makeBinaryOES(const std::vector<uint8_t> & binary,GLenum binaryFormat)205     void makeBinaryOES(const std::vector<uint8_t> &binary, GLenum binaryFormat)
206     {
207         mHandle = LoadBinaryProgramOES(binary, binaryFormat);
208     }
209 
makeBinaryES3(const std::vector<uint8_t> & binary,GLenum binaryFormat)210     void makeBinaryES3(const std::vector<uint8_t> &binary, GLenum binaryFormat)
211     {
212         mHandle = LoadBinaryProgramES3(binary, binaryFormat);
213     }
214 
valid()215     bool valid() const { return mHandle != 0; }
216 
get()217     GLuint get()
218     {
219         if (!mHandle)
220         {
221             makeEmpty();
222         }
223         return mHandle;
224     }
225 
reset()226     void reset()
227     {
228         if (mHandle)
229         {
230             glDeleteProgram(mHandle);
231             mHandle = 0;
232         }
233     }
234 
GLuint()235     operator GLuint() { return get(); }
236 
237   private:
238     GLuint mHandle;
239 };
240 
241 #define ANGLE_GL_EMPTY_PROGRAM(name) \
242     GLProgram name;                  \
243     name.makeEmpty();                \
244     ASSERT_TRUE(name.valid())
245 
246 #define ANGLE_GL_PROGRAM(name, vertex, fragment) \
247     GLProgram name;                              \
248     name.makeRaster(vertex, fragment);           \
249     ASSERT_TRUE(name.valid())
250 
251 #define ANGLE_GL_PROGRAM_WITH_GS(name, vertex, geometry, fragment) \
252     GLProgram name;                                                \
253     name.makeRaster(vertex, geometry, fragment);                   \
254     ASSERT_TRUE(name.valid())
255 
256 #define ANGLE_GL_PROGRAM_WITH_TESS(name, vertex, tcs, tes, fragment) \
257     GLProgram name;                                                  \
258     name.makeRaster(vertex, tcs, tes, fragment);                     \
259     ASSERT_TRUE(name.valid())
260 
261 #define ANGLE_GL_PROGRAM_TRANSFORM_FEEDBACK(name, vertex, fragment, tfVaryings, bufferMode) \
262     GLProgram name;                                                                         \
263     name.makeRasterWithTransformFeedback(vertex, fragment, tfVaryings, bufferMode);         \
264     ASSERT_TRUE(name.valid())
265 
266 #define ANGLE_GL_COMPUTE_PROGRAM(name, compute) \
267     GLProgram name;                             \
268     name.makeCompute(compute);                  \
269     ASSERT_TRUE(name.valid())
270 
271 #define ANGLE_GL_BINARY_OES_PROGRAM(name, binary, binaryFormat) \
272     GLProgram name;                                             \
273     name.makeBinaryOES(binary, binaryFormat);                   \
274     ASSERT_TRUE(name.valid())
275 
276 #define ANGLE_GL_BINARY_ES3_PROGRAM(name, binary, binaryFormat) \
277     GLProgram name;                                             \
278     name.makeBinaryES3(binary, binaryFormat);                   \
279     ASSERT_TRUE(name.valid())
280 
281 }  // namespace angle
282 
283 #endif  // ANGLE_TESTS_GL_RAII_H_
284