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
8 #include "IrrCompileConfig.h"
\r
10 #if defined(_IRR_COMPILE_WITH_OPENGL_) || defined(_IRR_COMPILE_WITH_OGLES1_) || defined(_IRR_COMPILE_WITH_OGLES2_)
\r
12 #include "IRenderTarget.h"
\r
19 template <class TOpenGLDriver, class TOpenGLTexture>
\r
20 class COpenGLCoreRenderTarget : public IRenderTarget
\r
23 COpenGLCoreRenderTarget(TOpenGLDriver* driver) : AssignedDepth(false), AssignedStencil(false), RequestTextureUpdate(false), RequestDepthStencilUpdate(false),
\r
24 BufferID(0), ColorAttachment(0), MultipleRenderTarget(0), Driver(driver)
\r
27 setDebugName("COpenGLCoreRenderTarget");
\r
30 DriverType = Driver->getDriverType();
\r
32 Size = Driver->getScreenSize();
\r
34 ColorAttachment = Driver->getFeature().ColorAttachment;
\r
35 MultipleRenderTarget = Driver->getFeature().MultipleRenderTarget;
\r
37 if (ColorAttachment > 0)
\r
38 Driver->irrGlGenFramebuffers(1, &BufferID);
\r
40 AssignedTextures.set_used(static_cast<u32>(ColorAttachment));
\r
42 for (u32 i = 0; i < AssignedTextures.size(); ++i)
\r
43 AssignedTextures[i] = GL_NONE;
\r
46 virtual ~COpenGLCoreRenderTarget()
\r
48 if (ColorAttachment > 0 && BufferID != 0)
\r
49 Driver->irrGlDeleteFramebuffers(1, &BufferID);
\r
51 for (u32 i = 0; i < Textures.size(); ++i)
\r
54 Textures[i]->drop();
\r
58 DepthStencil->drop();
\r
61 void setTextures(ITexture* const * textures, u32 numTextures, ITexture* depthStencil, const E_CUBE_SURFACE* cubeSurfaces, u32 numCubeSurfaces) override
\r
63 bool needSizeUpdate = false;
\r
65 // Set color attachments.
\r
66 if (!Textures.equals(textures, numTextures) || !CubeSurfaces.equals(cubeSurfaces, numCubeSurfaces))
\r
68 needSizeUpdate = true;
\r
70 core::array<ITexture*> prevTextures(Textures);
\r
72 if (numTextures > static_cast<u32>(ColorAttachment))
\r
74 core::stringc message = "This GPU supports up to ";
\r
75 message += static_cast<u32>(ColorAttachment);
\r
76 message += " textures per render target.";
\r
78 os::Printer::log(message.c_str(), ELL_WARNING);
\r
81 Textures.set_used(core::min_(numTextures, static_cast<u32>(ColorAttachment)));
\r
83 for (u32 i = 0; i < Textures.size(); ++i)
\r
85 TOpenGLTexture* currentTexture = (textures[i] && textures[i]->getDriverType() == DriverType) ? static_cast<TOpenGLTexture*>(textures[i]) : 0;
\r
87 GLuint textureID = 0;
\r
91 textureID = currentTexture->getOpenGLTextureName();
\r
96 Textures[i] = textures[i];
\r
97 Textures[i]->grab();
\r
105 for (u32 i = 0; i < prevTextures.size(); ++i)
\r
107 if (prevTextures[i])
\r
108 prevTextures[i]->drop();
\r
111 RequestTextureUpdate = true;
\r
114 if (!CubeSurfaces.equals(cubeSurfaces, numCubeSurfaces))
\r
116 CubeSurfaces.set_data(cubeSurfaces, numCubeSurfaces);
\r
117 RequestTextureUpdate = true;
\r
120 // Set depth and stencil attachments.
\r
121 if (DepthStencil != depthStencil)
\r
125 DepthStencil->drop();
\r
129 needSizeUpdate = true;
\r
130 TOpenGLTexture* currentTexture = (depthStencil && depthStencil->getDriverType() == DriverType) ? static_cast<TOpenGLTexture*>(depthStencil) : 0;
\r
132 if (currentTexture)
\r
134 if (currentTexture->getType() == ETT_2D)
\r
136 GLuint textureID = currentTexture->getOpenGLTextureName();
\r
138 const ECOLOR_FORMAT textureFormat = (textureID != 0) ? depthStencil->getColorFormat() : ECF_UNKNOWN;
\r
139 if (IImage::isDepthFormat(textureFormat))
\r
141 DepthStencil = depthStencil;
\r
142 DepthStencil->grab();
\r
146 os::Printer::log("Ignoring depth/stencil texture without depth color format.", ELL_WARNING);
\r
151 os::Printer::log("This driver doesn't support depth/stencil to cubemaps.", ELL_WARNING);
\r
155 RequestDepthStencilUpdate = true;
\r
158 if (needSizeUpdate)
\r
160 // Set size required for a viewport.
\r
162 ITexture* firstTexture = getTexture();
\r
165 Size = firstTexture->getSize();
\r
169 Size = DepthStencil->getSize();
\r
171 Size = Driver->getScreenSize();
\r
178 if (RequestTextureUpdate || RequestDepthStencilUpdate)
\r
180 // Set color attachments.
\r
182 if (RequestTextureUpdate)
\r
184 // Set new color textures.
\r
186 const u32 textureSize = core::min_(Textures.size(), AssignedTextures.size());
\r
188 for (u32 i = 0; i < textureSize; ++i)
\r
190 TOpenGLTexture* currentTexture = static_cast<TOpenGLTexture*>(Textures[i]);
\r
191 GLuint textureID = currentTexture ? currentTexture->getOpenGLTextureName() : 0;
\r
193 if (textureID != 0)
\r
195 AssignedTextures[i] = GL_COLOR_ATTACHMENT0 + i;
\r
196 GLenum textarget = currentTexture->getType() == ETT_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_POSITIVE_X + (int)CubeSurfaces[i];
\r
197 Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, AssignedTextures[i], textarget, textureID, 0);
\r
199 Driver->testGLError(__LINE__);
\r
202 else if (AssignedTextures[i] != GL_NONE)
\r
204 AssignedTextures[i] = GL_NONE;
\r
205 Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, AssignedTextures[i], GL_TEXTURE_2D, 0, 0);
\r
207 os::Printer::log("Error: Could not set render target.", ELL_ERROR);
\r
211 // Reset other render target channels.
\r
213 for (u32 i = textureSize; i < AssignedTextures.size(); ++i)
\r
215 if (AssignedTextures[i] != GL_NONE)
\r
217 Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, AssignedTextures[i], GL_TEXTURE_2D, 0, 0);
\r
218 AssignedTextures[i] = GL_NONE;
\r
222 RequestTextureUpdate = false;
\r
225 // Set depth and stencil attachments.
\r
227 if (RequestDepthStencilUpdate)
\r
229 const ECOLOR_FORMAT textureFormat = (DepthStencil) ? DepthStencil->getColorFormat() : ECF_UNKNOWN;
\r
231 if (IImage::isDepthFormat(textureFormat))
\r
233 GLuint textureID = static_cast<TOpenGLTexture*>(DepthStencil)->getOpenGLTextureName();
\r
235 #ifdef _IRR_EMSCRIPTEN_PLATFORM_ // The WEBGL_depth_texture extension does not allow attaching stencil+depth separate.
\r
236 if (textureFormat == ECF_D24S8)
\r
238 GLenum attachment = 0x821A; // GL_DEPTH_STENCIL_ATTACHMENT
\r
239 Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, textureID, 0);
\r
240 AssignedStencil = true;
\r
244 Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, textureID, 0);
\r
245 AssignedStencil = false;
\r
248 Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, textureID, 0);
\r
250 if (textureFormat == ECF_D24S8)
\r
252 Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, textureID, 0);
\r
254 AssignedStencil = true;
\r
258 if (AssignedStencil)
\r
259 Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
\r
261 AssignedStencil = false;
\r
264 AssignedDepth = true;
\r
269 Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
\r
271 if (AssignedStencil)
\r
272 Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
\r
274 AssignedDepth = false;
\r
275 AssignedStencil = false;
\r
278 Driver->testGLError(__LINE__);
\r
281 RequestDepthStencilUpdate = false;
\r
284 // Configure drawing operation.
\r
286 if (ColorAttachment > 0 && BufferID != 0)
\r
288 const u32 textureSize = Textures.size();
\r
290 if (textureSize == 0)
\r
291 Driver->irrGlDrawBuffer(GL_NONE);
\r
292 else if (textureSize == 1 || MultipleRenderTarget == 0)
\r
293 Driver->irrGlDrawBuffer(GL_COLOR_ATTACHMENT0);
\r
296 const u32 bufferCount = core::min_(MultipleRenderTarget, core::min_(textureSize, AssignedTextures.size()));
\r
298 Driver->irrGlDrawBuffers(bufferCount, AssignedTextures.pointer());
\r
302 Driver->testGLError(__LINE__);
\r
313 GLuint getBufferID() const
\r
318 const core::dimension2d<u32>& getSize() const
\r
323 ITexture* getTexture() const
\r
325 for (u32 i = 0; i < Textures.size(); ++i)
\r
328 return Textures[i];
\r
335 bool checkFBO(TOpenGLDriver* driver)
\r
337 if (ColorAttachment == 0)
\r
340 GLenum status = driver->irrGlCheckFramebufferStatus(GL_FRAMEBUFFER);
\r
344 case GL_FRAMEBUFFER_COMPLETE:
\r
346 case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
\r
347 os::Printer::log("FBO has invalid read buffer", ELL_ERROR);
\r
349 case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
\r
350 os::Printer::log("FBO has invalid draw buffer", ELL_ERROR);
\r
352 case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
\r
353 os::Printer::log("FBO has one or several incomplete image attachments", ELL_ERROR);
\r
355 case GL_FRAMEBUFFER_INCOMPLETE_FORMATS:
\r
356 os::Printer::log("FBO has one or several image attachments with different internal formats", ELL_ERROR);
\r
358 case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
\r
359 os::Printer::log("FBO has one or several image attachments with different dimensions", ELL_ERROR);
\r
361 case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
\r
362 os::Printer::log("FBO missing an image attachment", ELL_ERROR);
\r
364 case GL_FRAMEBUFFER_UNSUPPORTED:
\r
365 os::Printer::log("FBO format unsupported", ELL_ERROR);
\r
368 os::Printer::log("FBO error", ELL_ERROR);
\r
375 core::array<GLenum> AssignedTextures;
\r
376 bool AssignedDepth;
\r
377 bool AssignedStencil;
\r
379 bool RequestTextureUpdate;
\r
380 bool RequestDepthStencilUpdate;
\r
384 core::dimension2d<u32> Size;
\r
386 u32 ColorAttachment;
\r
387 u32 MultipleRenderTarget;
\r
389 TOpenGLDriver* Driver;
\r