1
0

CCFrameBuffer.cpp 14 KB

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