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
5 #ifndef __C_OGLCORE_RENDER_TARGET_H_INCLUDED__
\r
6 #define __C_OGLCORE_RENDER_TARGET_H_INCLUDED__
\r
9 #if defined(_IRR_COMPILE_WITH_OPENGL_) || defined(_IRR_COMPILE_WITH_OGLES1_) || defined(_IRR_COMPILE_WITH_OGLES2_)
\r
11 #include "IRenderTarget.h"
\r
13 #ifndef GL_FRAMEBUFFER_INCOMPLETE_FORMATS
\r
14 #define GL_FRAMEBUFFER_INCOMPLETE_FORMATS GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT
\r
17 #ifndef GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS
\r
18 #define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT
\r
26 template <class TOpenGLDriver, class TOpenGLTexture>
\r
27 class COpenGLCoreRenderTarget : public IRenderTarget
\r
30 COpenGLCoreRenderTarget(TOpenGLDriver* driver) : AssignedDepth(false), AssignedStencil(false), RequestTextureUpdate(false), RequestDepthStencilUpdate(false),
\r
31 BufferID(0), ColorAttachment(0), MultipleRenderTarget(0), Driver(driver)
\r
34 setDebugName("COpenGLCoreRenderTarget");
\r
37 DriverType = Driver->getDriverType();
\r
39 Size = Driver->getScreenSize();
\r
41 ColorAttachment = Driver->getFeature().ColorAttachment;
\r
42 MultipleRenderTarget = Driver->getFeature().MultipleRenderTarget;
\r
44 if (ColorAttachment > 0)
\r
45 Driver->irrGlGenFramebuffers(1, &BufferID);
\r
47 AssignedTextures.set_used(static_cast<u32>(ColorAttachment));
\r
49 for (u32 i = 0; i < AssignedTextures.size(); ++i)
\r
50 AssignedTextures[i] = GL_NONE;
\r
53 virtual ~COpenGLCoreRenderTarget()
\r
55 if (ColorAttachment > 0 && BufferID != 0)
\r
56 Driver->irrGlDeleteFramebuffers(1, &BufferID);
\r
58 for (u32 i = 0; i < Textures.size(); ++i)
\r
61 Textures[i]->drop();
\r
65 DepthStencil->drop();
\r
68 void setTextures(ITexture* const * textures, u32 numTextures, ITexture* depthStencil, const E_CUBE_SURFACE* cubeSurfaces, u32 numCubeSurfaces) override
\r
70 bool needSizeUpdate = false;
\r
72 // Set color attachments.
\r
73 if (!Textures.equals(textures, numTextures) || !CubeSurfaces.equals(cubeSurfaces, numCubeSurfaces))
\r
75 needSizeUpdate = true;
\r
77 core::array<ITexture*> prevTextures(Textures);
\r
79 if (numTextures > static_cast<u32>(ColorAttachment))
\r
81 core::stringc message = "This GPU supports up to ";
\r
82 message += static_cast<u32>(ColorAttachment);
\r
83 message += " textures per render target.";
\r
85 os::Printer::log(message.c_str(), ELL_WARNING);
\r
88 Textures.set_used(core::min_(numTextures, static_cast<u32>(ColorAttachment)));
\r
90 for (u32 i = 0; i < Textures.size(); ++i)
\r
92 TOpenGLTexture* currentTexture = (textures[i] && textures[i]->getDriverType() == DriverType) ? static_cast<TOpenGLTexture*>(textures[i]) : 0;
\r
94 GLuint textureID = 0;
\r
98 textureID = currentTexture->getOpenGLTextureName();
\r
101 if (textureID != 0)
\r
103 Textures[i] = textures[i];
\r
104 Textures[i]->grab();
\r
112 for (u32 i = 0; i < prevTextures.size(); ++i)
\r
114 if (prevTextures[i])
\r
115 prevTextures[i]->drop();
\r
118 RequestTextureUpdate = true;
\r
121 if (!CubeSurfaces.equals(cubeSurfaces, numCubeSurfaces))
\r
123 CubeSurfaces.set_data(cubeSurfaces, numCubeSurfaces);
\r
124 RequestTextureUpdate = true;
\r
127 // Set depth and stencil attachments.
\r
128 if (DepthStencil != depthStencil)
\r
132 DepthStencil->drop();
\r
136 needSizeUpdate = true;
\r
137 TOpenGLTexture* currentTexture = (depthStencil && depthStencil->getDriverType() == DriverType) ? static_cast<TOpenGLTexture*>(depthStencil) : 0;
\r
139 if (currentTexture)
\r
141 if (currentTexture->getType() == ETT_2D)
\r
143 GLuint textureID = currentTexture->getOpenGLTextureName();
\r
145 const ECOLOR_FORMAT textureFormat = (textureID != 0) ? depthStencil->getColorFormat() : ECF_UNKNOWN;
\r
146 if (IImage::isDepthFormat(textureFormat))
\r
148 DepthStencil = depthStencil;
\r
149 DepthStencil->grab();
\r
153 os::Printer::log("Ignoring depth/stencil texture without depth color format.", ELL_WARNING);
\r
158 os::Printer::log("This driver doesn't support depth/stencil to cubemaps.", ELL_WARNING);
\r
162 RequestDepthStencilUpdate = true;
\r
165 if (needSizeUpdate)
\r
167 // Set size required for a viewport.
\r
169 ITexture* firstTexture = getTexture();
\r
172 Size = firstTexture->getSize();
\r
176 Size = DepthStencil->getSize();
\r
178 Size = Driver->getScreenSize();
\r
185 if (RequestTextureUpdate || RequestDepthStencilUpdate)
\r
187 // Set color attachments.
\r
189 if (RequestTextureUpdate)
\r
191 // Set new color textures.
\r
193 const u32 textureSize = core::min_(Textures.size(), AssignedTextures.size());
\r
195 for (u32 i = 0; i < textureSize; ++i)
\r
197 TOpenGLTexture* currentTexture = static_cast<TOpenGLTexture*>(Textures[i]);
\r
198 GLuint textureID = currentTexture ? currentTexture->getOpenGLTextureName() : 0;
\r
200 if (textureID != 0)
\r
202 AssignedTextures[i] = GL_COLOR_ATTACHMENT0 + i;
\r
203 GLenum textarget = currentTexture->getType() == ETT_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_POSITIVE_X + (int)CubeSurfaces[i];
\r
204 Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, AssignedTextures[i], textarget, textureID, 0);
\r
206 Driver->testGLError(__LINE__);
\r
209 else if (AssignedTextures[i] != GL_NONE)
\r
211 AssignedTextures[i] = GL_NONE;
\r
212 Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, AssignedTextures[i], GL_TEXTURE_2D, 0, 0);
\r
214 os::Printer::log("Error: Could not set render target.", ELL_ERROR);
\r
218 // Reset other render target channels.
\r
220 for (u32 i = textureSize; i < AssignedTextures.size(); ++i)
\r
222 if (AssignedTextures[i] != GL_NONE)
\r
224 Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, AssignedTextures[i], GL_TEXTURE_2D, 0, 0);
\r
225 AssignedTextures[i] = GL_NONE;
\r
229 RequestTextureUpdate = false;
\r
232 // Set depth and stencil attachments.
\r
234 if (RequestDepthStencilUpdate)
\r
236 const ECOLOR_FORMAT textureFormat = (DepthStencil) ? DepthStencil->getColorFormat() : ECF_UNKNOWN;
\r
238 if (IImage::isDepthFormat(textureFormat))
\r
240 GLuint textureID = static_cast<TOpenGLTexture*>(DepthStencil)->getOpenGLTextureName();
\r
242 #ifdef _IRR_EMSCRIPTEN_PLATFORM_ // The WEBGL_depth_texture extension does not allow attaching stencil+depth separate.
\r
243 if (textureFormat == ECF_D24S8)
\r
245 GLenum attachment = 0x821A; // GL_DEPTH_STENCIL_ATTACHMENT
\r
246 Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, textureID, 0);
\r
247 AssignedStencil = true;
\r
251 Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, textureID, 0);
\r
252 AssignedStencil = false;
\r
255 Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, textureID, 0);
\r
257 if (textureFormat == ECF_D24S8)
\r
259 Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, textureID, 0);
\r
261 AssignedStencil = true;
\r
265 if (AssignedStencil)
\r
266 Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
\r
268 AssignedStencil = false;
\r
271 AssignedDepth = true;
\r
276 Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
\r
278 if (AssignedStencil)
\r
279 Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
\r
281 AssignedDepth = false;
\r
282 AssignedStencil = false;
\r
285 Driver->testGLError(__LINE__);
\r
288 RequestDepthStencilUpdate = false;
\r
291 // Configure drawing operation.
\r
293 if (ColorAttachment > 0 && BufferID != 0)
\r
295 const u32 textureSize = Textures.size();
\r
297 if (textureSize == 0)
\r
298 Driver->irrGlDrawBuffer(GL_NONE);
\r
299 else if (textureSize == 1 || MultipleRenderTarget == 0)
\r
300 Driver->irrGlDrawBuffer(GL_COLOR_ATTACHMENT0);
\r
303 const u32 bufferCount = core::min_(MultipleRenderTarget, core::min_(textureSize, AssignedTextures.size()));
\r
305 Driver->irrGlDrawBuffers(bufferCount, AssignedTextures.pointer());
\r
309 Driver->testGLError(__LINE__);
\r
320 GLuint getBufferID() const
\r
325 const core::dimension2d<u32>& getSize() const
\r
330 ITexture* getTexture() const
\r
332 for (u32 i = 0; i < Textures.size(); ++i)
\r
335 return Textures[i];
\r
342 bool checkFBO(TOpenGLDriver* driver)
\r
344 if (ColorAttachment == 0)
\r
347 GLenum status = driver->irrGlCheckFramebufferStatus(GL_FRAMEBUFFER);
\r
351 case GL_FRAMEBUFFER_COMPLETE:
\r
353 case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
\r
354 os::Printer::log("FBO has invalid read buffer", ELL_ERROR);
\r
356 case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
\r
357 os::Printer::log("FBO has invalid draw buffer", ELL_ERROR);
\r
359 case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
\r
360 os::Printer::log("FBO has one or several incomplete image attachments", ELL_ERROR);
\r
362 case GL_FRAMEBUFFER_INCOMPLETE_FORMATS:
\r
363 os::Printer::log("FBO has one or several image attachments with different internal formats", ELL_ERROR);
\r
365 case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
\r
366 os::Printer::log("FBO has one or several image attachments with different dimensions", ELL_ERROR);
\r
368 case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
\r
369 os::Printer::log("FBO missing an image attachment", ELL_ERROR);
\r
371 case GL_FRAMEBUFFER_UNSUPPORTED:
\r
372 os::Printer::log("FBO format unsupported", ELL_ERROR);
\r
375 os::Printer::log("FBO error", ELL_ERROR);
\r
382 core::array<GLenum> AssignedTextures;
\r
383 bool AssignedDepth;
\r
384 bool AssignedStencil;
\r
386 bool RequestTextureUpdate;
\r
387 bool RequestDepthStencilUpdate;
\r
391 core::dimension2d<u32> Size;
\r
393 u32 ColorAttachment;
\r
394 u32 MultipleRenderTarget;
\r
396 TOpenGLDriver* Driver;
\r