]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/COpenGLCoreRenderTarget.h
Fix OpenGL3 driver to compile standalone
[irrlicht.git] / source / Irrlicht / COpenGLCoreRenderTarget.h
1 // Copyright (C) 2015 Patryk Nadrowski\r
2 // This file is part of the "Irrlicht Engine".\r
3 // For conditions of distribution and use, see copyright notice in irrlicht.h\r
4 \r
5 #ifndef __C_OGLCORE_RENDER_TARGET_H_INCLUDED__\r
6 #define __C_OGLCORE_RENDER_TARGET_H_INCLUDED__\r
7 \r
8 \r
9 #include "IRenderTarget.h"\r
10 \r
11 #ifndef GL_FRAMEBUFFER_INCOMPLETE_FORMATS\r
12 #define GL_FRAMEBUFFER_INCOMPLETE_FORMATS GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT\r
13 #endif\r
14 \r
15 #ifndef GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS\r
16 #define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT\r
17 #endif\r
18 \r
19 namespace irr\r
20 {\r
21 namespace video\r
22 {\r
23 \r
24 template <class TOpenGLDriver, class TOpenGLTexture>\r
25 class COpenGLCoreRenderTarget : public IRenderTarget\r
26 {\r
27 public:\r
28         COpenGLCoreRenderTarget(TOpenGLDriver* driver) : AssignedDepth(false), AssignedStencil(false), RequestTextureUpdate(false), RequestDepthStencilUpdate(false),\r
29                 BufferID(0), ColorAttachment(0), MultipleRenderTarget(0), Driver(driver)\r
30         {\r
31 #ifdef _DEBUG\r
32                 setDebugName("COpenGLCoreRenderTarget");\r
33 #endif\r
34 \r
35                 DriverType = Driver->getDriverType();\r
36 \r
37                 Size = Driver->getScreenSize();\r
38 \r
39                 ColorAttachment = Driver->getFeature().ColorAttachment;\r
40                 MultipleRenderTarget = Driver->getFeature().MultipleRenderTarget;\r
41 \r
42                 if (ColorAttachment > 0)\r
43                         Driver->irrGlGenFramebuffers(1, &BufferID);\r
44 \r
45                 AssignedTextures.set_used(static_cast<u32>(ColorAttachment));\r
46 \r
47                 for (u32 i = 0; i < AssignedTextures.size(); ++i)\r
48                         AssignedTextures[i] = GL_NONE;\r
49         }\r
50 \r
51         virtual ~COpenGLCoreRenderTarget()\r
52         {\r
53                 if (ColorAttachment > 0 && BufferID != 0)\r
54                         Driver->irrGlDeleteFramebuffers(1, &BufferID);\r
55 \r
56                 for (u32 i = 0; i < Textures.size(); ++i)\r
57                 {\r
58                         if (Textures[i])\r
59                                 Textures[i]->drop();\r
60                 }\r
61 \r
62                 if (DepthStencil)\r
63                         DepthStencil->drop();\r
64         }\r
65 \r
66         void setTextures(ITexture* const * textures, u32 numTextures, ITexture* depthStencil, const E_CUBE_SURFACE* cubeSurfaces, u32 numCubeSurfaces) override\r
67         {\r
68                 bool needSizeUpdate = false;\r
69 \r
70                 // Set color attachments.\r
71                 if (!Textures.equals(textures, numTextures) || !CubeSurfaces.equals(cubeSurfaces, numCubeSurfaces))\r
72                 {\r
73                         needSizeUpdate = true;\r
74 \r
75                         core::array<ITexture*> prevTextures(Textures);\r
76 \r
77                         if (numTextures > static_cast<u32>(ColorAttachment))\r
78                         {\r
79                                 core::stringc message = "This GPU supports up to ";\r
80                                 message += static_cast<u32>(ColorAttachment);\r
81                                 message += " textures per render target.";\r
82 \r
83                                 os::Printer::log(message.c_str(), ELL_WARNING);\r
84                         }\r
85 \r
86                         Textures.set_used(core::min_(numTextures, static_cast<u32>(ColorAttachment)));\r
87 \r
88                         for (u32 i = 0; i < Textures.size(); ++i)\r
89                         {\r
90                                 TOpenGLTexture* currentTexture = (textures[i] && textures[i]->getDriverType() == DriverType) ? static_cast<TOpenGLTexture*>(textures[i]) : 0;\r
91 \r
92                                 GLuint textureID = 0;\r
93 \r
94                                 if (currentTexture)\r
95                                 {\r
96                                         textureID = currentTexture->getOpenGLTextureName();\r
97                                 }\r
98 \r
99                                 if (textureID != 0)\r
100                                 {\r
101                                         Textures[i] = textures[i];\r
102                                         Textures[i]->grab();\r
103                                 }\r
104                                 else\r
105                                 {\r
106                                         Textures[i] = 0;\r
107                                 }\r
108                         }\r
109 \r
110                         for (u32 i = 0; i < prevTextures.size(); ++i)\r
111                         {\r
112                                 if (prevTextures[i])\r
113                                         prevTextures[i]->drop();\r
114                         }\r
115 \r
116                         RequestTextureUpdate = true;\r
117                 }\r
118 \r
119                 if (!CubeSurfaces.equals(cubeSurfaces, numCubeSurfaces))\r
120                 {\r
121                         CubeSurfaces.set_data(cubeSurfaces, numCubeSurfaces);\r
122                         RequestTextureUpdate = true;\r
123                 }\r
124 \r
125                 // Set depth and stencil attachments.\r
126                 if (DepthStencil != depthStencil)\r
127                 {\r
128                         if (DepthStencil)\r
129                         {\r
130                                 DepthStencil->drop();\r
131                                 DepthStencil = 0;\r
132                         }\r
133 \r
134                         needSizeUpdate = true;\r
135                         TOpenGLTexture* currentTexture = (depthStencil && depthStencil->getDriverType() == DriverType) ? static_cast<TOpenGLTexture*>(depthStencil) : 0;\r
136 \r
137                         if (currentTexture)\r
138                         {       \r
139                                 if (currentTexture->getType() == ETT_2D)\r
140                                 {\r
141                                         GLuint textureID = currentTexture->getOpenGLTextureName();\r
142 \r
143                                         const ECOLOR_FORMAT textureFormat = (textureID != 0) ? depthStencil->getColorFormat() : ECF_UNKNOWN;\r
144                                         if (IImage::isDepthFormat(textureFormat))\r
145                                         {\r
146                                                 DepthStencil = depthStencil;\r
147                                                 DepthStencil->grab();\r
148                                         }\r
149                                         else\r
150                                         {\r
151                                                 os::Printer::log("Ignoring depth/stencil texture without depth color format.", ELL_WARNING);\r
152                                         }\r
153                                 }\r
154                                 else\r
155                                 {\r
156                                         os::Printer::log("This driver doesn't support depth/stencil to cubemaps.", ELL_WARNING);\r
157                                 }\r
158                         }\r
159 \r
160                         RequestDepthStencilUpdate = true;\r
161                 }\r
162 \r
163                 if (needSizeUpdate)\r
164                 {\r
165                         // Set size required for a viewport.\r
166 \r
167                         ITexture* firstTexture = getTexture();\r
168 \r
169                         if (firstTexture)\r
170                                 Size = firstTexture->getSize();\r
171                         else\r
172                         {\r
173                                 if (DepthStencil)\r
174                                         Size = DepthStencil->getSize();\r
175                                 else\r
176                                         Size = Driver->getScreenSize();\r
177                         }\r
178                 }\r
179         }\r
180 \r
181         void update()\r
182         {\r
183                 if (RequestTextureUpdate || RequestDepthStencilUpdate)\r
184                 {\r
185                         // Set color attachments.\r
186 \r
187                         if (RequestTextureUpdate)\r
188                         {\r
189                                 // Set new color textures.\r
190 \r
191                                 const u32 textureSize = core::min_(Textures.size(), AssignedTextures.size());\r
192 \r
193                                 for (u32 i = 0; i < textureSize; ++i)\r
194                                 {\r
195                                         TOpenGLTexture* currentTexture = static_cast<TOpenGLTexture*>(Textures[i]);\r
196                                         GLuint textureID = currentTexture ? currentTexture->getOpenGLTextureName() : 0;\r
197 \r
198                                         if (textureID != 0)\r
199                                         {\r
200                                                 AssignedTextures[i] = GL_COLOR_ATTACHMENT0 + i;\r
201                                                 GLenum textarget = currentTexture->getType() == ETT_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_POSITIVE_X + (int)CubeSurfaces[i];\r
202                                                 Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, AssignedTextures[i], textarget, textureID, 0);\r
203 #ifdef _DEBUG\r
204                                                 Driver->testGLError(__LINE__);\r
205 #endif\r
206                                         }\r
207                                         else if (AssignedTextures[i] != GL_NONE)\r
208                                         {\r
209                                                 AssignedTextures[i] = GL_NONE;\r
210                                                 Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, AssignedTextures[i], GL_TEXTURE_2D, 0, 0);\r
211 \r
212                                                 os::Printer::log("Error: Could not set render target.", ELL_ERROR);\r
213                                         }\r
214                                 }\r
215 \r
216                                 // Reset other render target channels.\r
217 \r
218                                 for (u32 i = textureSize; i < AssignedTextures.size(); ++i)\r
219                                 {\r
220                                         if (AssignedTextures[i] != GL_NONE)\r
221                                         {\r
222                                                 Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, AssignedTextures[i], GL_TEXTURE_2D, 0, 0);\r
223                                                 AssignedTextures[i] = GL_NONE;\r
224                                         }\r
225                                 }\r
226 \r
227                                 RequestTextureUpdate = false;\r
228                         }\r
229 \r
230                         // Set depth and stencil attachments.\r
231 \r
232                         if (RequestDepthStencilUpdate)\r
233                         {\r
234                                 const ECOLOR_FORMAT textureFormat = (DepthStencil) ? DepthStencil->getColorFormat() : ECF_UNKNOWN;\r
235 \r
236                                 if (IImage::isDepthFormat(textureFormat))\r
237                                 {\r
238                                         GLuint textureID = static_cast<TOpenGLTexture*>(DepthStencil)->getOpenGLTextureName();\r
239 \r
240 #ifdef _IRR_EMSCRIPTEN_PLATFORM_        // The WEBGL_depth_texture extension does not allow attaching stencil+depth separate.\r
241                                         if (textureFormat == ECF_D24S8)\r
242                                         {\r
243                                                 GLenum attachment = 0x821A; // GL_DEPTH_STENCIL_ATTACHMENT\r
244                                                 Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, textureID, 0);\r
245                                                 AssignedStencil = true;\r
246                                         }\r
247                                         else\r
248                                         {\r
249                                                 Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, textureID, 0);\r
250                                                 AssignedStencil = false;\r
251                                         }\r
252 #else\r
253                                         Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, textureID, 0);\r
254 \r
255                                         if (textureFormat == ECF_D24S8)\r
256                                         {\r
257                                                 Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, textureID, 0);\r
258 \r
259                                                 AssignedStencil = true;\r
260                                         }\r
261                                         else\r
262                                         {\r
263                                                 if (AssignedStencil)\r
264                                                         Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);\r
265 \r
266                                                 AssignedStencil = false;\r
267                                         }\r
268 #endif\r
269                                         AssignedDepth = true;\r
270                                 }\r
271                                 else\r
272                                 {\r
273                                         if (AssignedDepth)\r
274                                                 Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);\r
275 \r
276                                         if (AssignedStencil)\r
277                                                 Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);\r
278 \r
279                                         AssignedDepth = false;\r
280                                         AssignedStencil = false;\r
281                                 }\r
282 #ifdef _DEBUG\r
283                                 Driver->testGLError(__LINE__);\r
284 #endif\r
285 \r
286                                 RequestDepthStencilUpdate = false;\r
287                         }\r
288 \r
289                         // Configure drawing operation.\r
290 \r
291                         if (ColorAttachment > 0 && BufferID != 0)\r
292                         {\r
293                                 const u32 textureSize = Textures.size();\r
294 \r
295                                 if (textureSize == 0)\r
296                                         Driver->irrGlDrawBuffer(GL_NONE);\r
297                                 else if (textureSize == 1 || MultipleRenderTarget == 0)\r
298                                         Driver->irrGlDrawBuffer(GL_COLOR_ATTACHMENT0);\r
299                                 else\r
300                                 {\r
301                                         const u32 bufferCount = core::min_(MultipleRenderTarget, core::min_(textureSize, AssignedTextures.size()));\r
302 \r
303                                         Driver->irrGlDrawBuffers(bufferCount, AssignedTextures.pointer());\r
304                                 }\r
305 \r
306 #ifdef _DEBUG\r
307                                 Driver->testGLError(__LINE__);\r
308 #endif\r
309 \r
310                         }\r
311 \r
312 #ifdef _DEBUG\r
313                         checkFBO(Driver);\r
314 #endif\r
315                 }\r
316         }\r
317 \r
318         GLuint getBufferID() const\r
319         {\r
320                 return BufferID;\r
321         }\r
322 \r
323         const core::dimension2d<u32>& getSize() const\r
324         {\r
325                 return Size;\r
326         }\r
327 \r
328         ITexture* getTexture() const\r
329         {\r
330                 for (u32 i = 0; i < Textures.size(); ++i)\r
331                 {\r
332                         if (Textures[i])\r
333                                 return Textures[i];\r
334                 }\r
335 \r
336                 return 0;\r
337         }\r
338 \r
339 protected:\r
340         bool checkFBO(TOpenGLDriver* driver)\r
341         {\r
342                 if (ColorAttachment == 0)\r
343                         return true;\r
344 \r
345                 GLenum status = driver->irrGlCheckFramebufferStatus(GL_FRAMEBUFFER);\r
346 \r
347                 switch (status)\r
348                 {\r
349                         case GL_FRAMEBUFFER_COMPLETE:\r
350                                 return true;\r
351                         case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:\r
352                                 os::Printer::log("FBO has invalid read buffer", ELL_ERROR);\r
353                                 break;\r
354                         case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:\r
355                                 os::Printer::log("FBO has invalid draw buffer", ELL_ERROR);\r
356                                 break;\r
357                         case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:\r
358                                 os::Printer::log("FBO has one or several incomplete image attachments", ELL_ERROR);\r
359                                 break;\r
360                         case GL_FRAMEBUFFER_INCOMPLETE_FORMATS:\r
361                                 os::Printer::log("FBO has one or several image attachments with different internal formats", ELL_ERROR);\r
362                                 break;\r
363                         case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:\r
364                                 os::Printer::log("FBO has one or several image attachments with different dimensions", ELL_ERROR);\r
365                                 break;\r
366                         case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:\r
367                                 os::Printer::log("FBO missing an image attachment", ELL_ERROR);\r
368                                 break;\r
369                         case GL_FRAMEBUFFER_UNSUPPORTED:\r
370                                 os::Printer::log("FBO format unsupported", ELL_ERROR);\r
371                                 break;\r
372                         default:\r
373                                 os::Printer::log("FBO error", ELL_ERROR);\r
374                                 break;\r
375                 }\r
376 \r
377                 return false;\r
378         }\r
379 \r
380         core::array<GLenum> AssignedTextures;\r
381         bool AssignedDepth;\r
382         bool AssignedStencil;\r
383 \r
384         bool RequestTextureUpdate;\r
385         bool RequestDepthStencilUpdate;\r
386 \r
387         GLuint BufferID;\r
388 \r
389         core::dimension2d<u32> Size;\r
390 \r
391         u32 ColorAttachment;\r
392         u32 MultipleRenderTarget;\r
393 \r
394         TOpenGLDriver* Driver;\r
395 };\r
396 \r
397 }\r
398 }\r
399 \r
400 #endif\r