CCFrameBuffer.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. /****************************************************************************
  2. Copyright (c) 2015-2016 Chukong Technologies Inc.
  3. Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
  4. http://www.cocos2d-x.org
  5. Permission is hereby granted, free of charge, to any person obtaining a copy
  6. of this software and associated documentation files (the "Software"), to deal
  7. in the Software without restriction, including without limitation the rights
  8. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. copies of the Software, and to permit persons to whom the Software is
  10. furnished to do so, subject to the following conditions:
  11. The above copyright notice and this permission notice shall be included in
  12. all copies or substantial portions of the Software.
  13. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  19. THE SOFTWARE.
  20. ****************************************************************************/
  21. #include "renderer/CCFrameBuffer.h"
  22. #include "renderer/CCRenderer.h"
  23. #include "base/CCDirector.h"
  24. #include "base/CCEventCustom.h"
  25. #include "base/CCEventListenerCustom.h"
  26. #include "base/CCEventDispatcher.h"
  27. #include "base/CCEventType.h"
  28. NS_CC_BEGIN
  29. namespace experimental{
  30. FrameBuffer* FrameBuffer::_defaultFBO = nullptr;
  31. std::set<FrameBuffer*> FrameBuffer::_frameBuffers;
  32. Viewport::Viewport(float left, float bottom, float width, float height)
  33. : _left(left)
  34. , _bottom(bottom)
  35. , _width(width)
  36. , _height(height)
  37. {
  38. }
  39. Viewport::Viewport()
  40. {
  41. _left = _bottom = 0.f;
  42. _width = _height = 1.0f;
  43. }
  44. RenderTargetBase::RenderTargetBase()
  45. {
  46. }
  47. RenderTargetBase::~RenderTargetBase()
  48. {
  49. }
  50. bool RenderTargetBase::init(unsigned int width, unsigned int height)
  51. {
  52. _width = width;
  53. _height = height;
  54. return true;
  55. }
  56. RenderTarget* RenderTarget::create(unsigned int width, unsigned int height, Texture2D::PixelFormat format/* = Texture2D::PixelFormat::RGBA8888*/)
  57. {
  58. auto result = new (std::nothrow) RenderTarget();
  59. if(result && result->init(width, height,format))
  60. {
  61. result->autorelease();
  62. return result;
  63. }
  64. else
  65. {
  66. CC_SAFE_DELETE(result);
  67. return nullptr;
  68. }
  69. }
  70. bool RenderTarget::init(unsigned int width, unsigned int height, Texture2D::PixelFormat format)
  71. {
  72. if(!RenderTargetBase::init(width, height))
  73. {
  74. return false;
  75. }
  76. _texture = new (std::nothrow) Texture2D();
  77. if(nullptr == _texture) return false;
  78. //TODO: FIX me, get the correct bit depth for pixelformat
  79. auto dataLen = width * height * 4;
  80. auto data = malloc(dataLen);
  81. if( nullptr == data) return false;
  82. memset(data, 0, dataLen);
  83. if(_texture->initWithData(data, dataLen, format, width, height, Size(width, height)))
  84. {
  85. _texture->autorelease();
  86. CC_SAFE_RETAIN(_texture);
  87. free(data);
  88. }
  89. else
  90. {
  91. CC_SAFE_DELETE(_texture);
  92. free(data);
  93. return false;
  94. }
  95. #if CC_ENABLE_CACHE_TEXTURE_DATA
  96. _rebuildTextureListener = EventListenerCustom::create(EVENT_RENDERER_RECREATED, [this](EventCustom* event){
  97. auto dataLen = _width * _height * 4;
  98. auto data = malloc(dataLen);
  99. _texture->initWithData(data, dataLen,_texture->getPixelFormat(), _width, _height, Size(_width, _height));
  100. free(data);
  101. CCLOG("RenderTarget Texture recreated is %d", _texture->getName());
  102. });
  103. Director::getInstance()->getEventDispatcher()->addEventListenerWithFixedPriority(_rebuildTextureListener, -1);
  104. #endif
  105. return true;
  106. }
  107. RenderTarget::RenderTarget()
  108. : _texture(nullptr)
  109. #if CC_ENABLE_CACHE_TEXTURE_DATA
  110. , _rebuildTextureListener(nullptr)
  111. #endif
  112. {
  113. _type = Type::Texture2D;
  114. }
  115. RenderTarget::~RenderTarget()
  116. {
  117. CC_SAFE_RELEASE_NULL(_texture);
  118. #if CC_ENABLE_CACHE_TEXTURE_DATA
  119. Director::getInstance()->getEventDispatcher()->removeEventListener(_rebuildTextureListener);
  120. #endif
  121. }
  122. RenderTargetRenderBuffer::RenderTargetRenderBuffer()
  123. : _format(GL_RGBA4)
  124. , _colorBuffer(0)
  125. #if CC_ENABLE_CACHE_TEXTURE_DATA
  126. , _reBuildRenderBufferListener(nullptr)
  127. #endif
  128. {
  129. _type = Type::RenderBuffer;
  130. }
  131. RenderTargetRenderBuffer::~RenderTargetRenderBuffer()
  132. {
  133. if(glIsRenderbuffer(_colorBuffer))
  134. {
  135. glDeleteRenderbuffers(1, &_colorBuffer);
  136. _colorBuffer = 0;
  137. }
  138. #if CC_ENABLE_CACHE_TEXTURE_DATA
  139. Director::getInstance()->getEventDispatcher()->removeEventListener(_reBuildRenderBufferListener);
  140. #endif
  141. }
  142. bool RenderTargetRenderBuffer::init(unsigned int width, unsigned int height)
  143. {
  144. if(!RenderTargetBase::init(width, height)) return false;
  145. GLint oldRenderBuffer(0);
  146. glGetIntegerv(GL_RENDERBUFFER_BINDING, &oldRenderBuffer);
  147. //generate depthStencil
  148. glGenRenderbuffers(1, &_colorBuffer);
  149. glBindRenderbuffer(GL_RENDERBUFFER, _colorBuffer);
  150. //todo: this could have a param
  151. glRenderbufferStorage(GL_RENDERBUFFER, _format, width, height);
  152. glBindRenderbuffer(GL_RENDERBUFFER, oldRenderBuffer);
  153. #if CC_ENABLE_CACHE_TEXTURE_DATA
  154. _reBuildRenderBufferListener = EventListenerCustom::create(EVENT_RENDERER_RECREATED, [this](EventCustom* event){
  155. /** listen the event that renderer was recreated on Android/WP8 */
  156. GLint oldRenderBuffer(0);
  157. glGetIntegerv(GL_RENDERBUFFER_BINDING, &oldRenderBuffer);
  158. glGenRenderbuffers(1, &_colorBuffer);
  159. //generate depthStencil
  160. glBindRenderbuffer(GL_RENDERBUFFER, _colorBuffer);
  161. glRenderbufferStorage(GL_RENDERBUFFER, _format, _width, _height);
  162. glBindRenderbuffer(GL_RENDERBUFFER, oldRenderBuffer);
  163. CCLOG("RenderTargetRenderBuffer recreated, _colorBuffer is %d", _colorBuffer);
  164. });
  165. Director::getInstance()->getEventDispatcher()->addEventListenerWithFixedPriority(_reBuildRenderBufferListener, -1);
  166. #endif
  167. return true;
  168. }
  169. RenderTargetRenderBuffer* RenderTargetRenderBuffer::create(unsigned int width, unsigned int height)
  170. {
  171. auto result = new (std::nothrow) RenderTargetRenderBuffer();
  172. if(result && result->init(width, height))
  173. {
  174. result->autorelease();
  175. return result;
  176. }
  177. else
  178. {
  179. CC_SAFE_DELETE(result);
  180. return nullptr;
  181. }
  182. }
  183. RenderTargetDepthStencil::RenderTargetDepthStencil()
  184. : _depthStencilBuffer(0)
  185. #if CC_ENABLE_CACHE_TEXTURE_DATA
  186. , _reBuildDepthStencilListener(nullptr)
  187. #endif
  188. {
  189. _type = Type::RenderBuffer;
  190. }
  191. RenderTargetDepthStencil::~RenderTargetDepthStencil()
  192. {
  193. if(glIsRenderbuffer(_depthStencilBuffer))
  194. {
  195. glDeleteRenderbuffers(1, &_depthStencilBuffer);
  196. _depthStencilBuffer = 0;
  197. }
  198. #if CC_ENABLE_CACHE_TEXTURE_DATA
  199. Director::getInstance()->getEventDispatcher()->removeEventListener(_reBuildDepthStencilListener);
  200. #endif
  201. }
  202. bool RenderTargetDepthStencil::init(unsigned int width, unsigned int height)
  203. {
  204. if(!RenderTargetBase::init(width, height)) return false;
  205. GLint oldRenderBuffer(0);
  206. glGetIntegerv(GL_RENDERBUFFER_BINDING, &oldRenderBuffer);
  207. //generate depthStencil
  208. glGenRenderbuffers(1, &_depthStencilBuffer);
  209. glBindRenderbuffer(GL_RENDERBUFFER, _depthStencilBuffer);
  210. glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
  211. glBindRenderbuffer(GL_RENDERBUFFER, oldRenderBuffer);
  212. #if CC_ENABLE_CACHE_TEXTURE_DATA
  213. _reBuildDepthStencilListener = EventListenerCustom::create(EVENT_RENDERER_RECREATED, [this](EventCustom* event){
  214. /** listen the event that renderer was recreated on Android/WP8 */
  215. GLint oldRenderBuffer(0);
  216. glGetIntegerv(GL_RENDERBUFFER_BINDING, &oldRenderBuffer);
  217. glGenRenderbuffers(1, &_depthStencilBuffer);
  218. //generate depthStencil
  219. glBindRenderbuffer(GL_RENDERBUFFER, _depthStencilBuffer);
  220. glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, _width, _height);
  221. glBindRenderbuffer(GL_RENDERBUFFER, oldRenderBuffer);
  222. CCLOG("RenderTargetDepthStencil recreated, _depthStencilBuffer is %d", _depthStencilBuffer);
  223. });
  224. Director::getInstance()->getEventDispatcher()->addEventListenerWithFixedPriority(_reBuildDepthStencilListener, -1);
  225. #endif
  226. return true;
  227. }
  228. RenderTargetDepthStencil* RenderTargetDepthStencil::create(unsigned int width, unsigned int height)
  229. {
  230. auto result = new (std::nothrow) RenderTargetDepthStencil();
  231. if(result && result->init(width, height))
  232. {
  233. result->autorelease();
  234. return result;
  235. }
  236. else
  237. {
  238. CC_SAFE_DELETE(result);
  239. return nullptr;
  240. }
  241. }
  242. bool FrameBuffer::initWithGLView(GLView* view)
  243. {
  244. if(view == nullptr)
  245. {
  246. return false;
  247. }
  248. GLint fbo;
  249. glGetIntegerv(GL_FRAMEBUFFER_BINDING, &fbo);
  250. _fbo = fbo;
  251. return true;
  252. }
  253. FrameBuffer* FrameBuffer::getOrCreateDefaultFBO(GLView* view)
  254. {
  255. if(nullptr == _defaultFBO)
  256. {
  257. auto result = new (std::nothrow) FrameBuffer();
  258. if(result && result->initWithGLView(view))
  259. {
  260. result->autorelease();
  261. result->_isDefault = true;
  262. }
  263. else
  264. {
  265. CC_SAFE_DELETE(result);
  266. }
  267. _defaultFBO = result;
  268. }
  269. return _defaultFBO;
  270. }
  271. void FrameBuffer::applyDefaultFBO()
  272. {
  273. if(_defaultFBO)
  274. {
  275. _defaultFBO->applyFBO();
  276. }
  277. }
  278. void FrameBuffer::clearAllFBOs()
  279. {
  280. for (auto fbo : _frameBuffers)
  281. {
  282. fbo->clearFBO();
  283. }
  284. }
  285. FrameBuffer* FrameBuffer::create(uint8_t fid, unsigned int width, unsigned int height)
  286. {
  287. auto result = new (std::nothrow) FrameBuffer();
  288. if(result && result->init(fid, width, height))
  289. {
  290. result->autorelease();
  291. return result;
  292. }
  293. else
  294. {
  295. CC_SAFE_DELETE(result);
  296. return nullptr;
  297. }
  298. }
  299. bool FrameBuffer::init(uint8_t fid, unsigned int width, unsigned int height)
  300. {
  301. _fid = fid;
  302. _width = width;
  303. _height = height;
  304. GLint oldfbo;
  305. glGetIntegerv(GL_FRAMEBUFFER_BINDING, &oldfbo);
  306. glGenFramebuffers(1, &_fbo);
  307. glBindFramebuffer(GL_FRAMEBUFFER, _fbo);
  308. glBindFramebuffer(GL_FRAMEBUFFER, oldfbo);
  309. // _rt = RenderTarget::create(width, height);
  310. // if(nullptr == _rt) return false;
  311. #if CC_ENABLE_CACHE_TEXTURE_DATA
  312. _dirtyFBOListener = EventListenerCustom::create(EVENT_RENDERER_RECREATED, [this](EventCustom* event){
  313. if(isDefaultFBO()) return;
  314. GLint oldfbo;
  315. glGetIntegerv(GL_FRAMEBUFFER_BINDING, &oldfbo);
  316. glGenFramebuffers(1, &_fbo);
  317. glBindFramebuffer(GL_FRAMEBUFFER, _fbo);
  318. glBindFramebuffer(GL_FRAMEBUFFER, oldfbo);
  319. CCLOG("Recreate FrameBufferObject _fbo is %d", _fbo);
  320. _fboBindingDirty = true;
  321. });
  322. Director::getInstance()->getEventDispatcher()->addEventListenerWithFixedPriority(_dirtyFBOListener, -1);
  323. #endif
  324. return true;
  325. }
  326. FrameBuffer::FrameBuffer()
  327. : _fbo(0)
  328. , _previousFBO(0)
  329. , _fboBindingDirty(true)
  330. , _clearColor(Color4F(0, 0, 0, 1))
  331. , _clearDepth(1.0)
  332. , _clearStencil(0)
  333. , _rt(nullptr)
  334. , _rtDepthStencil(nullptr)
  335. , _isDefault(false)
  336. #if CC_ENABLE_CACHE_TEXTURE_DATA
  337. , _dirtyFBOListener(nullptr)
  338. #endif
  339. {
  340. _frameBuffers.insert(this);
  341. }
  342. FrameBuffer::~FrameBuffer()
  343. {
  344. {
  345. CC_SAFE_RELEASE_NULL(_rt);
  346. CC_SAFE_RELEASE_NULL(_rtDepthStencil);
  347. glDeleteFramebuffers(1, &_fbo);
  348. _fbo = 0;
  349. _frameBuffers.erase(this);
  350. #if CC_ENABLE_CACHE_TEXTURE_DATA
  351. Director::getInstance()->getEventDispatcher()->removeEventListener(_dirtyFBOListener);
  352. #endif
  353. if (isDefaultFBO())
  354. _defaultFBO = nullptr;
  355. }
  356. }
  357. void FrameBuffer::clearFBO()
  358. {
  359. applyFBO();
  360. glClearColor(_clearColor.r, _clearColor.g, _clearColor.b, _clearColor.a);
  361. glClearDepth(_clearDepth);
  362. glClearStencil(_clearStencil);
  363. glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
  364. restoreFBO();
  365. }
  366. void FrameBuffer::attachRenderTarget(RenderTargetBase* rt)
  367. {
  368. if(isDefaultFBO())
  369. {
  370. CCLOG("Can not apply render target to default FBO");
  371. return;
  372. }
  373. CC_ASSERT(rt);
  374. if(rt->getWidth() != _width || rt->getHeight() != _height)
  375. {
  376. CCLOG("Error, attach a render target with different size, Skip.");
  377. return;
  378. }
  379. CC_SAFE_RETAIN(rt);
  380. CC_SAFE_RELEASE(_rt);
  381. _rt = rt;
  382. _fboBindingDirty = true;
  383. }
  384. void FrameBuffer::applyFBO()
  385. {
  386. CHECK_GL_ERROR_DEBUG();
  387. glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&_previousFBO);
  388. glBindFramebuffer(GL_FRAMEBUFFER, _fbo);
  389. // CCASSERT(_fbo==0 || _fbo != _previousFBO, "calling applyFBO without restoring the previous one");
  390. CHECK_GL_ERROR_DEBUG();
  391. if(_fboBindingDirty && !isDefaultFBO())
  392. {
  393. CHECK_GL_ERROR_DEBUG();
  394. if(RenderTargetBase::Type::Texture2D == _rt->getType())
  395. glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _rt->getTexture()->getName(), 0);
  396. else
  397. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _rt->getBuffer());
  398. CHECK_GL_ERROR_DEBUG();
  399. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, nullptr == _rtDepthStencil ? 0 : _rtDepthStencil->getBuffer());
  400. CHECK_GL_ERROR_DEBUG();
  401. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, nullptr == _rtDepthStencil ? 0 : _rtDepthStencil->getBuffer());
  402. CHECK_GL_ERROR_DEBUG();
  403. CCLOG("FBO is %d _fbo %d color, %d ds", _fbo, RenderTargetBase::Type::Texture2D == _rt->getType() ? _rt->getTexture()->getName() : _rt->getBuffer(), nullptr == _rtDepthStencil ? 0 : _rtDepthStencil->getBuffer());
  404. _fboBindingDirty = false;
  405. }
  406. if(GL_FRAMEBUFFER_COMPLETE != glCheckFramebufferStatus(GL_FRAMEBUFFER))
  407. {
  408. CCLOG("FrameBuffer Status Error %d", (int)glCheckFramebufferStatus(GL_FRAMEBUFFER));
  409. }
  410. CHECK_GL_ERROR_DEBUG();
  411. }
  412. void FrameBuffer::restoreFBO()
  413. {
  414. glBindFramebuffer(GL_FRAMEBUFFER, _previousFBO);
  415. }
  416. void FrameBuffer::attachDepthStencilTarget(RenderTargetDepthStencil* rt)
  417. {
  418. if(isDefaultFBO())
  419. {
  420. CCLOG("Can not apply depth stencil target to default FBO");
  421. return;
  422. }
  423. if(nullptr != rt && (rt->getWidth() != _width || rt->getHeight() != _height))
  424. {
  425. CCLOG("Error, attach a render target Depth stencil with different size, Skip.");
  426. return;
  427. }
  428. CC_SAFE_RETAIN(rt);
  429. CC_SAFE_RELEASE(_rtDepthStencil);
  430. _rtDepthStencil = rt;
  431. _fboBindingDirty = true;
  432. }
  433. } //end of namespace experimental
  434. NS_CC_END