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
18 template <class TOpenGLDriver, class TOpenGLTexture>
\r
19 class COpenGLCoreRenderTarget : public IRenderTarget
\r
22 COpenGLCoreRenderTarget(TOpenGLDriver* driver) : AssignedDepth(false), AssignedStencil(false), RequestTextureUpdate(false), RequestDepthStencilUpdate(false),
\r
23 BufferID(0), ColorAttachment(0), MultipleRenderTarget(0), Driver(driver)
\r
26 setDebugName("COpenGLCoreRenderTarget");
\r
29 DriverType = Driver->getDriverType();
\r
31 Size = Driver->getScreenSize();
\r
33 ColorAttachment = Driver->getFeature().ColorAttachment;
\r
34 MultipleRenderTarget = Driver->getFeature().MultipleRenderTarget;
\r
36 if (ColorAttachment > 0)
\r
37 Driver->irrGlGenFramebuffers(1, &BufferID);
\r
39 AssignedTextures.set_used(static_cast<u32>(ColorAttachment));
\r
41 for (u32 i = 0; i < AssignedTextures.size(); ++i)
\r
42 AssignedTextures[i] = GL_NONE;
\r
45 virtual ~COpenGLCoreRenderTarget()
\r
47 if (ColorAttachment > 0 && BufferID != 0)
\r
48 Driver->irrGlDeleteFramebuffers(1, &BufferID);
\r
50 for (u32 i = 0; i < Textures.size(); ++i)
\r
53 Textures[i]->drop();
\r
57 DepthStencil->drop();
\r
60 void setTextures(ITexture* const * textures, u32 numTextures, ITexture* depthStencil, const E_CUBE_SURFACE* cubeSurfaces, u32 numCubeSurfaces) override
\r
62 bool needSizeUpdate = false;
\r
64 // Set color attachments.
\r
65 if (!Textures.equals(textures, numTextures) || !CubeSurfaces.equals(cubeSurfaces, numCubeSurfaces))
\r
67 needSizeUpdate = true;
\r
69 core::array<ITexture*> prevTextures(Textures);
\r
71 if (numTextures > static_cast<u32>(ColorAttachment))
\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
77 os::Printer::log(message.c_str(), ELL_WARNING);
\r
80 Textures.set_used(core::min_(numTextures, static_cast<u32>(ColorAttachment)));
\r
82 for (u32 i = 0; i < Textures.size(); ++i)
\r
84 TOpenGLTexture* currentTexture = (textures[i] && textures[i]->getDriverType() == DriverType) ? static_cast<TOpenGLTexture*>(textures[i]) : 0;
\r
86 GLuint textureID = 0;
\r
90 textureID = currentTexture->getOpenGLTextureName();
\r
95 Textures[i] = textures[i];
\r
96 Textures[i]->grab();
\r
104 for (u32 i = 0; i < prevTextures.size(); ++i)
\r
106 if (prevTextures[i])
\r
107 prevTextures[i]->drop();
\r
110 RequestTextureUpdate = true;
\r
113 if (!CubeSurfaces.equals(cubeSurfaces, numCubeSurfaces))
\r
115 CubeSurfaces.set_data(cubeSurfaces, numCubeSurfaces);
\r
116 RequestTextureUpdate = true;
\r
119 // Set depth and stencil attachments.
\r
120 if (DepthStencil != depthStencil)
\r
124 DepthStencil->drop();
\r
128 needSizeUpdate = true;
\r
129 TOpenGLTexture* currentTexture = (depthStencil && depthStencil->getDriverType() == DriverType) ? static_cast<TOpenGLTexture*>(depthStencil) : 0;
\r
131 if (currentTexture)
\r
133 if (currentTexture->getType() == ETT_2D)
\r
135 GLuint textureID = currentTexture->getOpenGLTextureName();
\r
137 const ECOLOR_FORMAT textureFormat = (textureID != 0) ? depthStencil->getColorFormat() : ECF_UNKNOWN;
\r
138 if (IImage::isDepthFormat(textureFormat))
\r
140 DepthStencil = depthStencil;
\r
141 DepthStencil->grab();
\r
145 os::Printer::log("Ignoring depth/stencil texture without depth color format.", ELL_WARNING);
\r
150 os::Printer::log("This driver doesn't support depth/stencil to cubemaps.", ELL_WARNING);
\r
154 RequestDepthStencilUpdate = true;
\r
157 if (needSizeUpdate)
\r
159 // Set size required for a viewport.
\r
161 ITexture* firstTexture = getTexture();
\r
164 Size = firstTexture->getSize();
\r
168 Size = DepthStencil->getSize();
\r
170 Size = Driver->getScreenSize();
\r
177 if (RequestTextureUpdate || RequestDepthStencilUpdate)
\r
179 // Set color attachments.
\r
181 if (RequestTextureUpdate)
\r
183 // Set new color textures.
\r
185 const u32 textureSize = core::min_(Textures.size(), AssignedTextures.size());
\r
187 for (u32 i = 0; i < textureSize; ++i)
\r
189 TOpenGLTexture* currentTexture = static_cast<TOpenGLTexture*>(Textures[i]);
\r
190 GLuint textureID = currentTexture ? currentTexture->getOpenGLTextureName() : 0;
\r
192 if (textureID != 0)
\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
198 Driver->testGLError(__LINE__);
\r
201 else if (AssignedTextures[i] != GL_NONE)
\r
203 AssignedTextures[i] = GL_NONE;
\r
204 Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, AssignedTextures[i], GL_TEXTURE_2D, 0, 0);
\r
206 os::Printer::log("Error: Could not set render target.", ELL_ERROR);
\r
210 // Reset other render target channels.
\r
212 for (u32 i = textureSize; i < AssignedTextures.size(); ++i)
\r
214 if (AssignedTextures[i] != GL_NONE)
\r
216 Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, AssignedTextures[i], GL_TEXTURE_2D, 0, 0);
\r
217 AssignedTextures[i] = GL_NONE;
\r
221 RequestTextureUpdate = false;
\r
224 // Set depth and stencil attachments.
\r
226 if (RequestDepthStencilUpdate)
\r
228 const ECOLOR_FORMAT textureFormat = (DepthStencil) ? DepthStencil->getColorFormat() : ECF_UNKNOWN;
\r
230 if (IImage::isDepthFormat(textureFormat))
\r
232 GLuint textureID = static_cast<TOpenGLTexture*>(DepthStencil)->getOpenGLTextureName();
\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
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
243 Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, textureID, 0);
\r
244 AssignedStencil = false;
\r
247 Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, textureID, 0);
\r
249 if (textureFormat == ECF_D24S8)
\r
251 Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, textureID, 0);
\r
253 AssignedStencil = true;
\r
257 if (AssignedStencil)
\r
258 Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
\r
260 AssignedStencil = false;
\r
263 AssignedDepth = true;
\r
268 Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
\r
270 if (AssignedStencil)
\r
271 Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
\r
273 AssignedDepth = false;
\r
274 AssignedStencil = false;
\r
277 Driver->testGLError(__LINE__);
\r
280 RequestDepthStencilUpdate = false;
\r
283 // Configure drawing operation.
\r
285 if (ColorAttachment > 0 && BufferID != 0)
\r
287 const u32 textureSize = Textures.size();
\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
295 const u32 bufferCount = core::min_(MultipleRenderTarget, core::min_(textureSize, AssignedTextures.size()));
\r
297 Driver->irrGlDrawBuffers(bufferCount, AssignedTextures.pointer());
\r
301 Driver->testGLError(__LINE__);
\r
312 GLuint getBufferID() const
\r
317 const core::dimension2d<u32>& getSize() const
\r
322 ITexture* getTexture() const
\r
324 for (u32 i = 0; i < Textures.size(); ++i)
\r
327 return Textures[i];
\r
334 bool checkFBO(TOpenGLDriver* driver)
\r
336 if (ColorAttachment == 0)
\r
339 GLenum status = driver->irrGlCheckFramebufferStatus(GL_FRAMEBUFFER);
\r
343 case GL_FRAMEBUFFER_COMPLETE:
\r
345 case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
\r
346 os::Printer::log("FBO has invalid read buffer", ELL_ERROR);
\r
348 case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
\r
349 os::Printer::log("FBO has invalid draw buffer", ELL_ERROR);
\r
351 case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
\r
352 os::Printer::log("FBO has one or several incomplete image attachments", ELL_ERROR);
\r
354 case GL_FRAMEBUFFER_INCOMPLETE_FORMATS:
\r
355 os::Printer::log("FBO has one or several image attachments with different internal formats", ELL_ERROR);
\r
357 case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
\r
358 os::Printer::log("FBO has one or several image attachments with different dimensions", ELL_ERROR);
\r
360 case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
\r
361 os::Printer::log("FBO missing an image attachment", ELL_ERROR);
\r
363 case GL_FRAMEBUFFER_UNSUPPORTED:
\r
364 os::Printer::log("FBO format unsupported", ELL_ERROR);
\r
367 os::Printer::log("FBO error", ELL_ERROR);
\r
374 core::array<GLenum> AssignedTextures;
\r
375 bool AssignedDepth;
\r
376 bool AssignedStencil;
\r
378 bool RequestTextureUpdate;
\r
379 bool RequestDepthStencilUpdate;
\r
383 core::dimension2d<u32> Size;
\r
385 u32 ColorAttachment;
\r
386 u32 MultipleRenderTarget;
\r
388 TOpenGLDriver* Driver;
\r