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