From 5a32bcfdaf96c5147a663143619f7555c229f0d5 Mon Sep 17 00:00:00 2001 From: HALX99 Date: Mon, 21 Sep 2020 07:10:50 -0700 Subject: [PATCH] RenderTarget abstract, in-progress (#210) RenderTarget abstract --- cocos/2d/CCGrid.cpp | 18 +- cocos/2d/CCGrid.h | 13 +- cocos/2d/CCRenderTexture.cpp | 42 ++- cocos/2d/CCRenderTexture.h | 11 +- cocos/base/CCDirector.cpp | 4 +- cocos/base/bitmask.h | 30 ++- cocos/base/ccTypes.h | 23 +- cocos/base/ccUtils.cpp | 4 +- cocos/platform/android/CCGL-android.h | 2 + cocos/platform/ios/CCGL-ios.h | 2 + cocos/platform/win32/CCGL-win32.h | 8 +- cocos/renderer/CCPipelineDescriptor.h | 2 +- cocos/renderer/CCRenderer.cpp | 181 ++++--------- cocos/renderer/CCRenderer.h | 45 ++-- cocos/renderer/CMakeLists.txt | 8 +- cocos/renderer/backend/Backend.h | 2 +- cocos/renderer/backend/CommandBuffer.h | 7 +- cocos/renderer/backend/Device.h | 10 +- cocos/renderer/backend/Macros.h | 2 +- .../renderer/backend/RenderPassDescriptor.cpp | 70 ----- cocos/renderer/backend/RenderPassParams.cpp | 42 +++ ...derPassDescriptor.h => RenderPassParams.h} | 41 ++- cocos/renderer/backend/RenderPipeline.h | 5 +- cocos/renderer/backend/RenderTarget.h | 72 +++++ cocos/renderer/backend/Texture.h | 5 +- cocos/renderer/backend/Types.h | 30 +++ .../renderer/backend/metal/CommandBufferMTL.h | 29 +- .../backend/metal/CommandBufferMTL.mm | 213 ++++++++------- cocos/renderer/backend/metal/DeviceMTL.h | 6 + cocos/renderer/backend/metal/DeviceMTL.mm | 22 ++ .../backend/metal/RenderPipelineMTL.h | 8 +- .../backend/metal/RenderPipelineMTL.mm | 65 ++--- .../renderer/backend/metal/RenderTargetMTL.h | 48 ++++ .../renderer/backend/metal/RenderTargetMTL.mm | 184 +++++++++++++ cocos/renderer/backend/metal/TextureMTL.h | 16 +- cocos/renderer/backend/metal/TextureMTL.mm | 9 +- cocos/renderer/backend/metal/UtilsMTL.h | 13 +- cocos/renderer/backend/metal/UtilsMTL.mm | 88 ------- .../backend/opengl/CommandBufferGL.cpp | 248 ++++++------------ .../renderer/backend/opengl/CommandBufferGL.h | 8 +- cocos/renderer/backend/opengl/DeviceGL.cpp | 22 ++ cocos/renderer/backend/opengl/DeviceGL.h | 6 + .../backend/opengl/RenderPipelineGL.cpp | 10 +- .../backend/opengl/RenderPipelineGL.h | 2 +- .../backend/opengl/RenderTargetGL.cpp | 109 ++++++++ .../renderer/backend/opengl/RenderTargetGL.h | 26 ++ cocos/renderer/backend/opengl/TextureGL.cpp | 4 +- cocos/renderer/backend/opengl/UtilsGL.cpp | 81 ------ cocos/renderer/backend/opengl/UtilsGL.h | 13 - .../lua-bindings/auto/lua_cocos2dx_auto.cpp | 21 +- cocos/ui/UITextFieldEx.h | 4 +- extensions/ImGuiEXT/CCImGuiEXT.cpp | 1 + extensions/cocostudio/CCDataReaderHelper.cpp | 4 - templates/cocos2dx_files.json | 4 +- tools/travis-scripts/run-script.sh | 2 +- 55 files changed, 1051 insertions(+), 894 deletions(-) delete mode 100644 cocos/renderer/backend/RenderPassDescriptor.cpp create mode 100644 cocos/renderer/backend/RenderPassParams.cpp rename cocos/renderer/backend/{RenderPassDescriptor.h => RenderPassParams.h} (65%) create mode 100644 cocos/renderer/backend/RenderTarget.h create mode 100644 cocos/renderer/backend/metal/RenderTargetMTL.h create mode 100644 cocos/renderer/backend/metal/RenderTargetMTL.mm create mode 100644 cocos/renderer/backend/opengl/RenderTargetGL.cpp create mode 100644 cocos/renderer/backend/opengl/RenderTargetGL.h diff --git a/cocos/2d/CCGrid.cpp b/cocos/2d/CCGrid.cpp index 3517a0b3a1..16b023c1de 100644 --- a/cocos/2d/CCGrid.cpp +++ b/cocos/2d/CCGrid.cpp @@ -34,6 +34,7 @@ THE SOFTWARE. #include "renderer/ccShaders.h" #include "renderer/backend/ProgramState.h" #include "renderer/backend/Device.h" +#include "renderer/backend/RenderTarget.h" #include "2d/CCCamera.h" @@ -154,6 +155,8 @@ GridBase::~GridBase() { CCLOGINFO("deallocing GridBase: %p", this); + CC_SAFE_RELEASE(_renderTarget); + //TODO: ? why 2.0 comments this line: setActive(false); CC_SAFE_RELEASE(_texture); @@ -216,16 +219,13 @@ void GridBase::beforeDraw() Size size = director->getWinSizeInPixels(); renderer->setViewPort(0, 0, (unsigned int)size.width, (unsigned int)size.height); - RenderTargetFlag flags = RenderTargetFlag::COLOR; - _oldColorAttachment = renderer->getColorAttachment(); - _oldDepthAttachment = renderer->getDepthAttachment(); - _oldStencilAttachment = renderer->getStencilAttachment(); - _oldRenderTargetFlag = renderer->getRenderTargetFlag(); - - renderer->setRenderTarget(flags, _texture, nullptr, nullptr); + _oldRenderTarget = renderer->getRenderTarget(); + CC_SAFE_RELEASE(_renderTarget); + _renderTarget = backend::Device::getInstance()->newRenderTarget(TargetBufferFlags::COLOR, _texture->getBackendTexture()); + renderer->setRenderTarget(_renderTarget); + renderer->clear(TargetBufferFlags::COLOR, _clearColor, 1, 0, 0.0); }; renderer->addCommand(&_beforeDrawCommand); - renderer->clear(ClearFlag::COLOR, _clearColor, 1, 0, 0.0); } void GridBase::afterDraw(cocos2d::Node * /*target*/) @@ -238,7 +238,7 @@ void GridBase::afterDraw(cocos2d::Node * /*target*/) director->setProjection(_directorProjection); const auto& vp = Camera::getDefaultViewport(); renderer->setViewPort(vp.x, vp.y, vp.w, vp.h); - renderer->setRenderTarget(_oldRenderTargetFlag, _oldColorAttachment, _oldDepthAttachment, _oldStencilAttachment); + renderer->setRenderTarget(_oldRenderTarget); }; renderer->addCommand(&_afterDrawCommand); diff --git a/cocos/2d/CCGrid.h b/cocos/2d/CCGrid.h index 37bc91b448..e7a20d5239 100644 --- a/cocos/2d/CCGrid.h +++ b/cocos/2d/CCGrid.h @@ -40,6 +40,11 @@ class Texture2D; // class GLProgram; class Node; +namespace backend +{ +class RenderTarget; +} + /** * @addtogroup _2d * @{ @@ -153,10 +158,10 @@ protected: CallbackCommand _afterDrawCommand; CallbackCommand _beforeBlitCommand; CallbackCommand _afterBlitCommand; - RenderTargetFlag _oldRenderTargetFlag; - Texture2D* _oldColorAttachment = nullptr; - Texture2D* _oldDepthAttachment = nullptr; - Texture2D* _oldStencilAttachment = nullptr; + + // New + backend::RenderTarget* _oldRenderTarget = nullptr; + backend::RenderTarget* _renderTarget = nullptr; backend::UniformLocation _mvpMatrixLocation; backend::UniformLocation _textureLocation; diff --git a/cocos/2d/CCRenderTexture.cpp b/cocos/2d/CCRenderTexture.cpp index af7ec8b3d9..60fcdac4b8 100644 --- a/cocos/2d/CCRenderTexture.cpp +++ b/cocos/2d/CCRenderTexture.cpp @@ -38,6 +38,7 @@ THE SOFTWARE. #include "renderer/CCTextureCache.h" #include "renderer/backend/Device.h" #include "renderer/backend/Texture.h" +#include "renderer/backend/RenderTarget.h" NS_CC_BEGIN @@ -57,6 +58,7 @@ RenderTexture::RenderTexture() RenderTexture::~RenderTexture() { + CC_SAFE_RELEASE(_renderTarget); CC_SAFE_RELEASE(_sprite); CC_SAFE_RELEASE(_texture2DCopy); CC_SAFE_RELEASE(_depthStencilTexture); @@ -207,8 +209,6 @@ bool RenderTexture::initWithWidthAndHeight(int w, int h, backend::PixelFormat fo _renderTargetFlags = RenderTargetFlag::COLOR; - clearColorAttachment(); - if (PixelFormat::D24S8 == depthStencilFormat) { _renderTargetFlags = RenderTargetFlag::ALL; @@ -228,6 +228,14 @@ bool RenderTexture::initWithWidthAndHeight(int w, int h, backend::PixelFormat fo texture->release(); } + _renderTarget = backend::Device::getInstance()->newRenderTarget(_renderTargetFlags, + _texture2D ? _texture2D->getBackendTexture() : nullptr, + _depthStencilTexture ? _depthStencilTexture->getBackendTexture() : nullptr, + _depthStencilTexture ? _depthStencilTexture->getBackendTexture() : nullptr + ); + + clearColorAttachment(); + _texture2D->setAntiAliasTexParameters(); if (_texture2DCopy) { @@ -477,7 +485,7 @@ void RenderTexture::newImage(std::function)> imageCallback, b int savedBufferHeight = (int)s.height; bool hasPremultipliedAlpha = _texture2D->hasPremultipliedAlpha(); - _director->getRenderer()->readPixels(_texture2D->getBackendTexture(), [=](const backend::PixelBufferDescriptor& pbd) { + _director->getRenderer()->readPixels(_renderTarget, [=](const backend::PixelBufferDescriptor& pbd) { if(pbd) { auto image = utils::makeInstance(&Image::initWithRawData, pbd._data.getBytes(), pbd._data.getSize(), pbd._width, pbd._height, 8, hasPremultipliedAlpha); imageCallback(image); @@ -548,12 +556,8 @@ void RenderTexture::onBegin() _oldViewport = renderer->getViewport(); renderer->setViewPort(viewport.origin.x, viewport.origin.y, viewport.size.width, viewport.size.height); - _oldColorAttachment = renderer->getColorAttachment(); - _oldDepthAttachment = renderer->getDepthAttachment(); - _oldStencilAttachment = renderer->getStencilAttachment(); - _oldRenderTargetFlag = renderer->getRenderTargetFlag(); - - renderer->setRenderTarget(_renderTargetFlags, _texture2D, _depthStencilTexture, _depthStencilTexture); + _oldRenderTarget = renderer->getRenderTarget(); + renderer->setRenderTarget(_renderTarget); } void RenderTexture::onEnd() @@ -564,7 +568,8 @@ void RenderTexture::onEnd() Renderer *renderer = Director::getInstance()->getRenderer(); renderer->setViewPort(_oldViewport.x, _oldViewport.y, _oldViewport.w, _oldViewport.h); - renderer->setRenderTarget(_oldRenderTargetFlag, _oldColorAttachment, _oldDepthAttachment, _oldStencilAttachment); + + renderer->setRenderTarget(_oldRenderTarget); } void RenderTexture::begin() @@ -629,19 +634,10 @@ void RenderTexture::setClearFlags(ClearFlag clearFlags) void RenderTexture::clearColorAttachment() { auto renderer = _director->getRenderer(); - _beforeClearAttachmentCommand.func = [=]() -> void { - _oldColorAttachment = renderer->getColorAttachment(); - renderer->setRenderTarget(RenderTargetFlag::COLOR, _texture2D, nullptr, nullptr); - }; - renderer->addCommand(&_beforeClearAttachmentCommand); - - Color4F color(0.f, 0.f, 0.f, 0.f); - renderer->clear(ClearFlag::COLOR, color, 1, 0, _globalZOrder); - - _afterClearAttachmentCommand.func = [=]() -> void { - renderer->setRenderTarget(RenderTargetFlag::COLOR, _oldColorAttachment, nullptr, nullptr); - }; - renderer->addCommand(&_afterClearAttachmentCommand); + _oldRenderTarget = renderer->getRenderTarget(); + renderer->setRenderTarget(_renderTarget); + renderer->clear(TargetBufferFlags::COLOR, Color4F{0.f, 0.f, 0.f, 0.f}, 1, 0, _globalZOrder); + renderer->setRenderTarget(_oldRenderTarget); } NS_CC_END diff --git a/cocos/2d/CCRenderTexture.h b/cocos/2d/CCRenderTexture.h index 850f1020c3..4cc2ec80e0 100644 --- a/cocos/2d/CCRenderTexture.h +++ b/cocos/2d/CCRenderTexture.h @@ -39,6 +39,7 @@ NS_CC_BEGIN namespace backend { class TextureBackend; + class RenderTarget; } class EventCustom; @@ -358,11 +359,11 @@ protected: Texture2D* _texture2D = nullptr; Texture2D* _depthStencilTexture = nullptr; Texture2D* _texture2DCopy = nullptr; // a copy of _texture - Texture2D* _oldColorAttachment = nullptr; - Texture2D* _oldDepthAttachment = nullptr; - Texture2D* _oldStencilAttachment = nullptr; - RenderTargetFlag _renderTargetFlags; - RenderTargetFlag _oldRenderTargetFlag; + + backend::RenderTarget* _renderTarget = nullptr; + backend::RenderTarget* _oldRenderTarget = nullptr; + RenderTargetFlag _renderTargetFlags{}; + Image* _UITextureImage = nullptr; backend::PixelFormat _pixelFormat = backend::PixelFormat::RGBA8888; diff --git a/cocos/base/CCDirector.cpp b/cocos/base/CCDirector.cpp index 86d82ac865..b14fb2c2f7 100644 --- a/cocos/base/CCDirector.cpp +++ b/cocos/base/CCDirector.cpp @@ -388,13 +388,13 @@ void Director::setOpenGLView(GLView *openGLView) _isStatusLabelUpdated = true; + _renderer->init(); + if (_openGLView) { setGLDefaultValues(); } - _renderer->init(); - if (_eventDispatcher) { _eventDispatcher->setEnabled(true); diff --git a/cocos/base/bitmask.h b/cocos/base/bitmask.h index 009500adb9..8754e3212e 100644 --- a/cocos/base/bitmask.h +++ b/cocos/base/bitmask.h @@ -66,16 +66,11 @@ Copyright (c) 2020 c4games.com. return static_cast<_BITMASK>(~static_cast<_IntTy>(_Left)); \ } \ \ - constexpr bool _Bitmask_includes( \ - _BITMASK _Left, _BITMASK _Elements) noexcept { /* return (_Left & _Elements) != _BITMASK{} */ \ - return (_Left & _Elements) != _BITMASK{}; \ - } \ - \ - constexpr bool _Bitmask_includes_all( \ - _BITMASK _Left, _BITMASK _Elements) noexcept { /* return (_Left & _Elements) == _Elements */ \ - return (_Left & _Elements) == _Elements; \ + constexpr bool operator!(_BITMASK _Left) noexcept { /* return ~_Left */ \ + using _IntTy = _STD underlying_type<_BITMASK>::type; \ + return !static_cast<_IntTy>(_Left); \ } - + // BITSHIFT OPERATIONS, inspired from msvc++ . #define CC_ENABLE_BITSHIFT_OPS(_BITMASK) \ constexpr _BITMASK operator>>(_BITMASK _Left, _BITMASK _Right) noexcept { /* return _Left & _Right */ \ @@ -87,3 +82,20 @@ Copyright (c) 2020 c4games.com. using _IntTy = _STD underlying_type<_BITMASK>::type; \ return static_cast<_BITMASK>(static_cast<_IntTy>(_Left) << static_cast<_IntTy>(_Right)); \ } + +namespace bitmask { + template + constexpr bool none(_BITMASK _Left, _BITMASK _Elements) noexcept { + return !(_Left & _Elements); + } + + template + constexpr bool any(_BITMASK _Left, _BITMASK _Elements) noexcept { + return !!(_Left & _Elements); + } + + template + constexpr bool only(_BITMASK _Left, _BITMASK _Elements) noexcept { + return (_Left & _Elements) == _Elements; + } +} // namespace bitmask diff --git a/cocos/base/ccTypes.h b/cocos/base/ccTypes.h index 7484434373..f69c2c3a75 100644 --- a/cocos/base/ccTypes.h +++ b/cocos/base/ccTypes.h @@ -634,6 +634,7 @@ struct CC_DLL ScissorRect float height = 0; }; +// TODO: Move to renderer/backend/Types.h struct TextureFormatEXT { enum { @@ -652,27 +653,13 @@ struct TextureFlag }; }; -enum class ClearFlag : uint8_t -{ - NONE = 0, - COLOR = 1, - DEPTH = 1 << 1, - STENCIL = 1 << 2, - ALL = COLOR | DEPTH | STENCIL -}; -CC_ENABLE_BITMASK_OPS(ClearFlag) - -enum class RenderTargetFlag : uint8_t -{ - COLOR = 1, - DEPTH = 1 << 1, - STENCIL = 1 << 2, - ALL = COLOR | DEPTH | STENCIL -}; -CC_ENABLE_BITMASK_OPS(RenderTargetFlag) using TextureUsage = backend::TextureUsage; using PixelFormat = backend::PixelFormat; +using TargetBufferFlags = backend::TargetBufferFlags; +using RenderTargetFlag = backend::RenderTargetFlag; +using ClearFlag = backend::ClearFlag; + NS_CC_END // end group /// @} diff --git a/cocos/base/ccUtils.cpp b/cocos/base/ccUtils.cpp index b5dccb034f..e5796e1e6a 100644 --- a/cocos/base/ccUtils.cpp +++ b/cocos/base/ccUtils.cpp @@ -75,7 +75,6 @@ namespace utils * Capture screen interface */ static EventListenerCustom* s_captureScreenListener; -static CallbackCommand s_captureScreenCommand; void captureScreen(std::function)> imageCallback) { if (s_captureScreenListener) @@ -91,9 +90,8 @@ void captureScreen(std::function)> imageCallback) s_captureScreenListener = eventDispatcher->addCustomEventListener(Director::EVENT_AFTER_DRAW, [=](EventCustom* /*event*/) { eventDispatcher->removeEventListener(s_captureScreenListener); s_captureScreenListener = nullptr; - // !!!GL: AFTER_DRAW and BEFORE_END_FRAME - renderer->readPixels(nullptr, [=](const backend::PixelBufferDescriptor& pbd) { + renderer->readPixels(renderer->getDefaultRenderTarget(), [=](const backend::PixelBufferDescriptor& pbd) { if (pbd) { auto image = utils::makeInstance(&Image::initWithRawData, pbd._data.getBytes(), pbd._data.getSize(), pbd._width, pbd._height, 8, false); imageCallback(image); diff --git a/cocos/platform/android/CCGL-android.h b/cocos/platform/android/CCGL-android.h index ba5ca8f947..70a80de127 100644 --- a/cocos/platform/android/CCGL-android.h +++ b/cocos/platform/android/CCGL-android.h @@ -33,6 +33,8 @@ THE SOFTWARE. #define glUnmapBuffer glUnmapBufferOES #define GL_DEPTH24_STENCIL8 GL_DEPTH24_STENCIL8_OES +#define GL_DEPTH_STENCIL GL_DEPTH_STENCIL_OES +#define GL_UNSIGNED_INT_24_8 GL_UNSIGNED_INT_24_8_OES #define GL_WRITE_ONLY GL_WRITE_ONLY_OES // GL_GLEXT_PROTOTYPES isn't defined in glplatform.h on android ndk r7 diff --git a/cocos/platform/ios/CCGL-ios.h b/cocos/platform/ios/CCGL-ios.h index 7123be89a4..45f34c343d 100644 --- a/cocos/platform/ios/CCGL-ios.h +++ b/cocos/platform/ios/CCGL-ios.h @@ -38,6 +38,8 @@ THE SOFTWARE. #define glUnmapBuffer glUnmapBufferOES #define GL_DEPTH24_STENCIL8 GL_DEPTH24_STENCIL8_OES +#define GL_DEPTH_STENCIL GL_DEPTH_STENCIL_OES +#define GL_UNSIGNED_INT_24_8 GL_UNSIGNED_INT_24_8_OES #define GL_WRITE_ONLY GL_WRITE_ONLY_OES #include diff --git a/cocos/platform/win32/CCGL-win32.h b/cocos/platform/win32/CCGL-win32.h index ff66f07352..04ecc8cb92 100644 --- a/cocos/platform/win32/CCGL-win32.h +++ b/cocos/platform/win32/CCGL-win32.h @@ -32,6 +32,9 @@ THE SOFTWARE. #include "glad/glad.h" #if defined(CC_USE_GLES) +#undef GL_DEPTH_STENCIL +#undef GL_DEPTH24_STENCIL8 +#undef GL_UNSIGNED_INT_24_8 #undef glClearDepth #undef glMapBuffer #undef glUnmapBuffer @@ -57,6 +60,9 @@ THE SOFTWARE. #undef glGenerateMipmap #endif +#define GL_DEPTH_STENCIL GL_DEPTH_STENCIL_OES +#define GL_DEPTH24_STENCIL8 GL_DEPTH24_STENCIL8_OES +#define GL_UNSIGNED_INT_24_8 GL_UNSIGNED_INT_24_8_OES #define glClearDepth glClearDepthf #define glMapBuffer glMapBufferOES #define glUnmapBuffer glUnmapBufferOES @@ -84,6 +90,4 @@ THE SOFTWARE. #endif -#define CC_GL_DEPTH24_STENCIL8 GL_DEPTH24_STENCIL8 - #endif // CC_TARGET_PLATFORM == CC_PLATFORM_WIN32 diff --git a/cocos/renderer/CCPipelineDescriptor.h b/cocos/renderer/CCPipelineDescriptor.h index 2c3f602e27..21916dd6a4 100644 --- a/cocos/renderer/CCPipelineDescriptor.h +++ b/cocos/renderer/CCPipelineDescriptor.h @@ -27,7 +27,7 @@ #include "renderer/backend/DepthStencilState.h" #include "renderer/backend/Texture.h" #include "renderer/backend/VertexLayout.h" -#include "renderer/backend/RenderPassDescriptor.h" +#include "renderer/backend/RenderPassParams.h" #include "renderer/backend/ProgramState.h" #include diff --git a/cocos/renderer/CCRenderer.cpp b/cocos/renderer/CCRenderer.cpp index c4cd98823b..e610653c44 100644 --- a/cocos/renderer/CCRenderer.cpp +++ b/cocos/renderer/CCRenderer.cpp @@ -47,6 +47,7 @@ #include "xxhash.h" #include "renderer/backend/Backend.h" +#include "renderer/backend/RenderTarget.h" NS_CC_BEGIN @@ -180,6 +181,7 @@ Renderer::~Renderer() CC_SAFE_RELEASE(_commandBuffer); CC_SAFE_RELEASE(_renderPipeline); + CC_SAFE_RELEASE(_defaultRT); } void Renderer::init() @@ -191,6 +193,9 @@ void Renderer::init() auto device = backend::Device::getInstance(); _commandBuffer = device->newCommandBuffer(); + // MTL: default render target flags should have DEPTH_AND_STENCIL make sure further clear could set pipeline state properly + _defaultRT = device->newDefaultRenderTarget(TargetBufferFlags::COLOR | TargetBufferFlags::DEPTH_AND_STENCIL); + _currentRT = _defaultRT; _renderPipeline = device->newRenderPipeline(); _commandBuffer->setRenderPipeline(_renderPipeline); } @@ -404,7 +409,8 @@ void Renderer::clean() void Renderer::setDepthTest(bool value) { _depthStencilDescriptor.depthTestEnabled = value; - _renderPassDescriptor.depthTestEnabled = value; + _currentRT->modifyTargetFlags(value ? TargetBufferFlags::DEPTH : TargetBufferFlags::NONE, + value ? TargetBufferFlags::NONE : TargetBufferFlags::DEPTH); } void Renderer::setDepthWrite(bool value) @@ -435,7 +441,9 @@ bool Renderer::getDepthWrite() const void Renderer::setStencilTest(bool value) { _depthStencilDescriptor.stencilTestEnabled = value; - _renderPassDescriptor.stencilTestEnabled = value; + + _currentRT->modifyTargetFlags(value ? TargetBufferFlags::STENCIL : TargetBufferFlags::NONE, + value ? TargetBufferFlags::NONE : TargetBufferFlags::STENCIL); } void Renderer::setStencilCompareFunction(backend::CompareFunction func, unsigned int ref, unsigned int readMask) @@ -615,24 +623,30 @@ void Renderer::drawBatchedTriangles() _vertexBuffer->updateData(_verts, _filledVertex * sizeof(_verts[0])); _indexBuffer->updateData(_indices, _filledIndex * sizeof(_indices[0])); #endif - + /************** 2: Draw *************/ + beginRenderPass(); for (int i = 0; i < batchesTotal; ++i) { - beginRenderPass(_triBatchesToDraw[i].cmd); + + auto& drawInfo = _triBatchesToDraw[i]; + setRenderPipeline(drawInfo.cmd->getPipelineDescriptor(), _renderPassParams); _commandBuffer->setVertexBuffer(_vertexBuffer); _commandBuffer->setIndexBuffer(_indexBuffer); - auto& pipelineDescriptor = _triBatchesToDraw[i].cmd->getPipelineDescriptor(); + auto& pipelineDescriptor = drawInfo.cmd->getPipelineDescriptor(); _commandBuffer->setProgramState(pipelineDescriptor.programState); _commandBuffer->drawElements(backend::PrimitiveType::TRIANGLE, backend::IndexFormat::U_SHORT, - _triBatchesToDraw[i].indicesToDraw, - _triBatchesToDraw[i].offset * sizeof(_indices[0])); - _commandBuffer->endRenderPass(); + drawInfo.indicesToDraw, + drawInfo.offset * sizeof(_indices[0])); + _drawnBatches++; _drawnVertices += _triBatchesToDraw[i].indicesToDraw; + } + _commandBuffer->endRenderPass(); + /************** 3: Cleanup *************/ _queuedTriangleCommands.clear(); @@ -649,7 +663,8 @@ void Renderer::drawCustomCommand(RenderCommand *command) if (cmd->getBeforeCallback()) cmd->getBeforeCallback()(); - beginRenderPass(command); + beginRenderPass(); + setRenderPipeline(cmd->getPipelineDescriptor(), _renderPassParams); _commandBuffer->setVertexBuffer(cmd->getVertexBuffer()); _commandBuffer->setProgramState(cmd->getPipelineDescriptor().programState); @@ -738,21 +753,24 @@ bool Renderer::checkVisibility(const Mat4 &transform, const Size &size) return ret; } -void Renderer::readPixels(backend::TextureBackend* texture, std::function callback) +void Renderer::readPixels(backend::RenderTarget* rt, std::function callback) { - if(!texture) // read pixels from screen, metal renderer backend: screen texture must not be a framebufferOnly + assert(!!rt); + if(rt == _defaultRT) // read pixels from screen, metal renderer backend: screen texture must not be a framebufferOnly backend::Device::getInstance()->setFrameBufferOnly(false); - _commandBuffer->capture(texture, std::move(callback)); + + _commandBuffer->readPixels(rt, std::move(callback)); } -void Renderer::setRenderPipeline(const PipelineDescriptor& pipelineDescriptor, const backend::RenderPassDescriptor& renderPassDescriptor) +void Renderer::setRenderPipeline(const PipelineDescriptor& pipelineDescriptor, const backend::RenderPassParams& renderPassParams) { auto device = backend::Device::getInstance(); - _renderPipeline->update(pipelineDescriptor, renderPassDescriptor); + _renderPipeline->update(pipelineDescriptor, _currentRT, renderPassParams); backend::DepthStencilState* depthStencilState = nullptr; - auto needDepthStencilAttachment = renderPassDescriptor.depthTestEnabled || renderPassDescriptor.stencilTestEnabled; - if (needDepthStencilAttachment) + if (bitmask::any(_currentRT->getTargetFlags(), RenderTargetFlag::DEPTH_AND_STENCIL)) { + // FIXME: don't use autorelease at draw frame + // Now the depthStencilState is in autoreleasepool depthStencilState = device->createDepthStencilState(_depthStencilDescriptor); } _commandBuffer->setDepthStencilState(depthStencilState); @@ -761,125 +779,36 @@ void Renderer::setRenderPipeline(const PipelineDescriptor& pipelineDescriptor, c #endif } -void Renderer::beginRenderPass(RenderCommand* cmd) +void Renderer::beginRenderPass() { - _commandBuffer->beginRenderPass(_renderPassDescriptor); - _commandBuffer->setViewport(_viewport.x, _viewport.y, _viewport.w, _viewport.h); - _commandBuffer->setCullMode(_cullMode); - _commandBuffer->setWinding(_winding); - _commandBuffer->setScissorRect(_scissorState.isEnabled, _scissorState.rect.x, _scissorState.rect.y, _scissorState.rect.width, _scissorState.rect.height); - setRenderPipeline(cmd->getPipelineDescriptor(), _renderPassDescriptor); - + _commandBuffer->beginRenderPass(_currentRT, _renderPassParams); + _commandBuffer->setViewport(_viewport.x, _viewport.y, _viewport.w, _viewport.h); + _commandBuffer->setCullMode(_cullMode); + _commandBuffer->setWinding(_winding); + _commandBuffer->setScissorRect(_scissorState.isEnabled, _scissorState.rect.x, _scissorState.rect.y, _scissorState.rect.width, _scissorState.rect.height); _commandBuffer->setStencilReferenceValue(_stencilRef); } -void Renderer::setRenderTarget(RenderTargetFlag flags, Texture2D* colorAttachment, Texture2D* depthAttachment, Texture2D* stencilAttachment) -{ - _renderTargetFlag = flags; - if (_Bitmask_includes(RenderTargetFlag::COLOR, flags)) - { - _renderPassDescriptor.needColorAttachment = true; - if (colorAttachment) - _renderPassDescriptor.colorAttachmentsTexture[0] = colorAttachment->getBackendTexture(); - else - _renderPassDescriptor.colorAttachmentsTexture[0] = nullptr; - - _colorAttachment = colorAttachment; - } - else - { - _colorAttachment = nullptr; - _renderPassDescriptor.needColorAttachment = false; - _renderPassDescriptor.colorAttachmentsTexture[0] = nullptr; - } - - if (_Bitmask_includes(RenderTargetFlag::DEPTH, flags)) - { - _renderPassDescriptor.depthTestEnabled = true; - if (depthAttachment) - _renderPassDescriptor.depthAttachmentTexture = depthAttachment->getBackendTexture(); - else - _renderPassDescriptor.depthAttachmentTexture = nullptr; - - _depthAttachment = depthAttachment; - } - else - { - _renderPassDescriptor.depthTestEnabled = false; - _renderPassDescriptor.depthAttachmentTexture = nullptr; - _depthAttachment = nullptr; - } - - if (_Bitmask_includes(RenderTargetFlag::STENCIL, flags)) - { - _stencilAttachment = stencilAttachment; - _renderPassDescriptor.stencilTestEnabled = true; - if (_stencilAttachment) - _renderPassDescriptor.stencilAttachmentTexture = stencilAttachment->getBackendTexture(); - else - _renderPassDescriptor.stencilAttachmentTexture = nullptr; - } - else - { - _stencilAttachment = nullptr; - _renderPassDescriptor.stencilTestEnabled = false; - _renderPassDescriptor.stencilAttachmentTexture = nullptr; - } -} - void Renderer::clear(ClearFlag flags, const Color4F& color, float depth, unsigned int stencil, float globalOrder) { _clearFlag = flags; - CallbackCommand* command = new CallbackCommand(); - command->init(globalOrder); - command->func = [=]() -> void { - backend::RenderPassDescriptor descriptor; + backend::RenderPassParams descriptor; - if (_Bitmask_includes(ClearFlag::COLOR, flags)) - { - _clearColor = color; - descriptor.clearColorValue = {color.r, color.g, color.b, color.a}; - descriptor.needClearColor = true; - descriptor.needColorAttachment = true; - descriptor.colorAttachmentsTexture[0] = _renderPassDescriptor.colorAttachmentsTexture[0]; - } - if (_Bitmask_includes(ClearFlag::DEPTH, flags)) - { - descriptor.clearDepthValue = depth; - descriptor.needClearDepth = true; - descriptor.depthTestEnabled = true; - descriptor.depthAttachmentTexture = _renderPassDescriptor.depthAttachmentTexture; - } - if (_Bitmask_includes(ClearFlag::STENCIL, flags)) - { - descriptor.clearStencilValue = stencil; - descriptor.needClearStencil = true; - descriptor.stencilTestEnabled = true; - descriptor.stencilAttachmentTexture = _renderPassDescriptor.stencilAttachmentTexture; - } + descriptor.flags.clear = flags; + if (bitmask::any(flags, ClearFlag::COLOR)) { + _clearColor = color; + descriptor.clearColorValue = { color.r, color.g, color.b, color.a }; + } - _commandBuffer->beginRenderPass(descriptor); - _commandBuffer->endRenderPass(); + if(bitmask::any(flags, ClearFlag::DEPTH)) + descriptor.clearDepthValue = depth; - delete command; - }; - addCommand(command); -} + if(bitmask::any(flags, ClearFlag::STENCIL)) + descriptor.clearStencilValue = stencil; -Texture2D* Renderer::getColorAttachment() const -{ - return _colorAttachment; -} - -Texture2D* Renderer::getDepthAttachment() const -{ - return _depthAttachment; -} - -Texture2D* Renderer::getStencilAttachment() const -{ - return _stencilAttachment; + _commandBuffer->beginRenderPass(_currentRT, descriptor); + _commandBuffer->endRenderPass(); } const Color4F& Renderer::getClearColor() const @@ -889,12 +818,12 @@ const Color4F& Renderer::getClearColor() const float Renderer::getClearDepth() const { - return _renderPassDescriptor.clearDepthValue; + return _renderPassParams.clearDepthValue; } unsigned int Renderer::getClearStencil() const { - return _renderPassDescriptor.clearStencilValue; + return _renderPassParams.clearStencilValue; } ClearFlag Renderer::getClearFlag() const @@ -904,7 +833,7 @@ ClearFlag Renderer::getClearFlag() const RenderTargetFlag Renderer::getRenderTargetFlag() const { - return _renderTargetFlag; + return _currentRT->getTargetFlags(); } void Renderer::setScissorTest(bool enabled) diff --git a/cocos/renderer/CCRenderer.h b/cocos/renderer/CCRenderer.h index e20f38d698..55fbee24ab 100644 --- a/cocos/renderer/CCRenderer.h +++ b/cocos/renderer/CCRenderer.h @@ -50,6 +50,7 @@ class CommandBuffer; class RenderPipeline; class RenderPass; class TextureBackend; +class RenderTarget; struct RenderPipelineDescriptor; struct PixelBufferDescriptor; } @@ -187,7 +188,11 @@ public: @stencilAttachment The value to replace stencil attachment. Depth attachment and stencil attachment can be the same value. */ - void setRenderTarget(RenderTargetFlag flags, Texture2D* colorAttachment, Texture2D* depthAttachment, Texture2D* stencilAttachment); + backend::RenderTarget* getRenderTarget() const { return _currentRT; } + void setRenderTarget(backend::RenderTarget* rt) { _currentRT = rt; }; + + backend::RenderTarget* getDefaultRenderTarget() const { return _defaultRT; } + /** Set clear values for each attachment. @flags Flags to indicate which attachment clear value to be modified. @@ -197,24 +202,6 @@ public: */ void clear(ClearFlag flags, const Color4F& color, float depth, unsigned int stencil, float globalOrder); - /** - * Get color attachment. - * @return Color attachment. - */ - Texture2D* getColorAttachment() const; - - /** - * Get depth attachment. - * @return Depth attachment. - */ - Texture2D* getDepthAttachment() const; - - /** - * Get stencil attachment. - * @return Stencil attachment. - */ - Texture2D* getStencilAttachment() const; - /** * Get color clear value. * @return Color clear value. @@ -407,8 +394,8 @@ public: /** returns whether or not a rectangle is visible or not */ bool checkVisibility(const Mat4& transform, const Size& size); - /** read pixels from texture or screen framebuffer */ - void readPixels(backend::TextureBackend* texture, std::function callback); + /** read pixels from RenderTarget or screen framebuffer */ + void readPixels(backend::RenderTarget* rt, std::function callback); protected: friend class Director; @@ -474,15 +461,15 @@ protected: void doVisitRenderQueue(const std::vector&); void fillVerticesAndIndices(const TrianglesCommand* cmd, unsigned int vertexBufferOffset); - void beginRenderPass(RenderCommand*); /// Begin a render pass. + void beginRenderPass(); /// Begin a render pass. /** * Building a programmable pipeline involves an expensive evaluation of GPU state. * So a new render pipeline object will be created only if it hasn't been created before. * @param pipelineDescriptor Specifies the pipeline descriptor. - * @param renderPassDescriptor Specifies the render pass descriptor. + * @param renderPassParams Specifies the render pass descriptor. */ - void setRenderPipeline(const PipelineDescriptor&, const backend::RenderPassDescriptor&); + void setRenderPipeline(const PipelineDescriptor&, const backend::RenderPassParams&); void pushStateBlock(); @@ -508,7 +495,7 @@ protected: TriangleCommandBufferManager _triangleCommandBufferManager; backend::CommandBuffer* _commandBuffer = nullptr; - backend::RenderPassDescriptor _renderPassDescriptor; + backend::RenderPassParams _renderPassParams; backend::DepthStencilDescriptor _depthStencilDescriptor; // Internal structure that has the information for the batches @@ -541,13 +528,11 @@ protected: unsigned int _stencilRef = 0; - // weak reference - Texture2D* _colorAttachment = nullptr; - Texture2D* _depthAttachment = nullptr; - Texture2D* _stencilAttachment = nullptr; + backend::RenderTarget* _defaultRT = nullptr; + backend::RenderTarget* _currentRT = nullptr; // weak ref + Color4F _clearColor = Color4F::BLACK; ClearFlag _clearFlag; - RenderTargetFlag _renderTargetFlag = RenderTargetFlag::COLOR; struct ScissorState { diff --git a/cocos/renderer/CMakeLists.txt b/cocos/renderer/CMakeLists.txt index e4542b22e3..1b4975aecf 100644 --- a/cocos/renderer/CMakeLists.txt +++ b/cocos/renderer/CMakeLists.txt @@ -28,7 +28,7 @@ set(COCOS_RENDERER_HEADER renderer/backend/Program.h renderer/backend/ProgramCache.h renderer/backend/Macros.h - renderer/backend/RenderPassDescriptor.h + renderer/backend/RenderPassParams.h renderer/backend/RenderPipeline.h renderer/backend/RenderPipelineDescriptor.h renderer/backend/ShaderModule.h @@ -74,7 +74,7 @@ set(COCOS_RENDERER_SRC renderer/backend/ProgramState.cpp renderer/backend/ProgramStateRegistry.cpp renderer/backend/ShaderCache.cpp - renderer/backend/RenderPassDescriptor.cpp + renderer/backend/RenderPassParams.cpp ) if(ANDROID OR WINDOWS OR LINUX OR (IOS AND CC_FORCE_USE_GLES)) @@ -90,6 +90,7 @@ list(APPEND COCOS_RENDERER_HEADER renderer/backend/opengl/TextureGL.h renderer/backend/opengl/UtilsGL.h renderer/backend/opengl/DeviceInfoGL.h + renderer/backend/opengl/RenderTargetGL.h ) list(APPEND COCOS_RENDERER_SRC @@ -103,6 +104,7 @@ list(APPEND COCOS_RENDERER_SRC renderer/backend/opengl/TextureGL.cpp renderer/backend/opengl/UtilsGL.cpp renderer/backend/opengl/DeviceInfoGL.cpp + renderer/backend/opengl/RenderTargetGL.cpp ) else() @@ -111,6 +113,7 @@ list(APPEND COCOS_RENDERER_HEADER renderer/backend/metal/BufferMTL.h renderer/backend/metal/BufferManager.h renderer/backend/metal/CommandBufferMTL.h + renderer/backend/metal/RenderTargetMTL.h renderer/backend/metal/DepthStencilStateMTL.h renderer/backend/metal/DeviceMTL.h renderer/backend/metal/RenderPipelineMTL.h @@ -125,6 +128,7 @@ list(APPEND COCOS_RENDERER_SRC renderer/backend/metal/BufferMTL.mm renderer/backend/metal/BufferManager.mm renderer/backend/metal/CommandBufferMTL.mm + renderer/backend/metal/RenderTargetMTL.mm renderer/backend/metal/DepthStencilStateMTL.mm renderer/backend/metal/DeviceMTL.mm renderer/backend/metal/RenderPipelineMTL.mm diff --git a/cocos/renderer/backend/Backend.h b/cocos/renderer/backend/Backend.h index 755bc6614e..4b88859dbe 100644 --- a/cocos/renderer/backend/Backend.h +++ b/cocos/renderer/backend/Backend.h @@ -24,7 +24,7 @@ #pragma once -#include "renderer/backend/RenderPassDescriptor.h" +#include "renderer/backend/RenderPassParams.h" #include "renderer/backend/RenderPipeline.h" #include "renderer/backend/RenderPipelineDescriptor.h" #include "renderer/backend/Device.h" diff --git a/cocos/renderer/backend/CommandBuffer.h b/cocos/renderer/backend/CommandBuffer.h index ee94e99999..f9843cfcc9 100644 --- a/cocos/renderer/backend/CommandBuffer.h +++ b/cocos/renderer/backend/CommandBuffer.h @@ -31,7 +31,7 @@ #include "Macros.h" #include "Types.h" -#include "RenderPassDescriptor.h" +#include "RenderPassParams.h" #include "PixelBufferDescriptor.h" #include "CCStdC.h" #include "ProgramState.h" @@ -47,6 +47,7 @@ class RenderPipeline; class Buffer; class DepthStencilState; class TextureBackend; +class RenderTarget; /** * @addtogroup _backend @@ -70,7 +71,7 @@ public: * Begin a render pass, initial color, depth and stencil attachment. * @param descriptor Specifies a group of render targets that hold the results of a render pass. */ - virtual void beginRenderPass(const RenderPassDescriptor& descriptor) = 0; + virtual void beginRenderPass(const RenderTarget* renderTarget, const RenderPassParams& descriptor) = 0; /** * Sets the current render pipeline state object. @@ -172,7 +173,7 @@ public: * Get a screen snapshot * @param callback A callback to deal with screen snapshot image. */ - virtual void capture(TextureBackend* texture, std::function callback) = 0; + virtual void readPixels(RenderTarget* rt, std::function callback) = 0; /** * Update both front and back stencil reference value. diff --git a/cocos/renderer/backend/Device.h b/cocos/renderer/backend/Device.h index f5f516ef30..a3f86938d9 100644 --- a/cocos/renderer/backend/Device.h +++ b/cocos/renderer/backend/Device.h @@ -27,7 +27,7 @@ #include "Macros.h" #include "Types.h" #include "RenderPipelineDescriptor.h" -#include "RenderPassDescriptor.h" +#include "RenderPassParams.h" #include "Texture.h" #include "DepthStencilState.h" #include "ProgramCache.h" @@ -45,6 +45,7 @@ class Buffer; class ShaderModule; class RenderPipeline; class RenderPass; +class RenderTarget; /** * @addtogroup _backend @@ -89,6 +90,13 @@ public: */ virtual TextureBackend* newTexture(const TextureDescriptor& descriptor) = 0; + virtual RenderTarget* newDefaultRenderTarget(TargetBufferFlags rtf) = 0; + + virtual RenderTarget* newRenderTarget(TargetBufferFlags rtf, + TextureBackend* colorAttachment = nullptr, + TextureBackend* depthAttachment = nullptr, + TextureBackend* stencilAttachhment = nullptr) = 0; + /** * Create an auto released DepthStencilState object. * @param descriptor Specifies depth and stencil description. diff --git a/cocos/renderer/backend/Macros.h b/cocos/renderer/backend/Macros.h index 09bb9c0ffd..6b448dfdb2 100644 --- a/cocos/renderer/backend/Macros.h +++ b/cocos/renderer/backend/Macros.h @@ -27,7 +27,7 @@ #define CC_BACKEND_BEGIN namespace cocos2d{ namespace backend{ #define CC_BACKEND_END }} -#define MAX_COLOR_ATTCHMENT 1 +#define MAX_COLOR_ATTCHMENT 4 #define MAX_INFLIGHT_BUFFER 3 diff --git a/cocos/renderer/backend/RenderPassDescriptor.cpp b/cocos/renderer/backend/RenderPassDescriptor.cpp deleted file mode 100644 index a98adf5ea1..0000000000 --- a/cocos/renderer/backend/RenderPassDescriptor.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/**************************************************************************** - Copyright (c) 2018-2019 Xiamen Yaji Software Co., Ltd. - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -#include "RenderPassDescriptor.h" - -CC_BACKEND_BEGIN - -RenderPassDescriptor& RenderPassDescriptor::operator=(const RenderPassDescriptor& descriptor) -{ - clearDepthValue = descriptor.clearDepthValue; - clearStencilValue = descriptor.clearStencilValue; - clearColorValue = descriptor.clearColorValue; - needColorAttachment = descriptor.needColorAttachment; - depthTestEnabled = descriptor.depthTestEnabled; - stencilTestEnabled = descriptor.stencilTestEnabled; - needClearColor = descriptor.needClearColor; - needClearDepth = descriptor.needClearDepth; - needClearStencil = descriptor.needClearStencil; - depthAttachmentTexture = descriptor.depthAttachmentTexture; - stencilAttachmentTexture = descriptor.stencilAttachmentTexture; - colorAttachmentsTexture[0] = descriptor.colorAttachmentsTexture[0]; - - return *this; -} - -bool RenderPassDescriptor::operator==(const RenderPassDescriptor& descriptor) const -{ - if( clearDepthValue == descriptor.clearDepthValue && - clearStencilValue == descriptor.clearStencilValue && - clearColorValue == descriptor.clearColorValue && - needColorAttachment == descriptor.needColorAttachment && - depthTestEnabled == descriptor.depthTestEnabled && - stencilTestEnabled == descriptor.stencilTestEnabled && - needClearColor == descriptor.needClearColor && - needClearDepth == descriptor.needClearDepth && - needClearStencil == descriptor.needClearStencil && - depthAttachmentTexture == descriptor.depthAttachmentTexture && - stencilAttachmentTexture == descriptor.stencilAttachmentTexture && - colorAttachmentsTexture[0] == descriptor.colorAttachmentsTexture[0]) - { - return true; - } - else - { - return false; - } -} - -CC_BACKEND_END diff --git a/cocos/renderer/backend/RenderPassParams.cpp b/cocos/renderer/backend/RenderPassParams.cpp new file mode 100644 index 0000000000..5e6bcb733f --- /dev/null +++ b/cocos/renderer/backend/RenderPassParams.cpp @@ -0,0 +1,42 @@ +/**************************************************************************** + Copyright (c) 2018-2019 Xiamen Yaji Software Co., Ltd. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +#include "RenderPassParams.h" + +CC_BACKEND_BEGIN + +bool RenderPassParams::operator==(const RenderPassParams& descriptor) const +{ + return (clearDepthValue == descriptor.clearDepthValue && + clearStencilValue == descriptor.clearStencilValue && + clearColorValue == descriptor.clearColorValue && +// needColorAttachment == descriptor.needColorAttachment && +// depthTestEnabled == descriptor.depthTestEnabled && +// stencilTestEnabled == descriptor.stencilTestEnabled && + flags.clear == descriptor.flags.clear && + flags.discardStart == descriptor.flags.discardStart && + flags.discardEnd == descriptor.flags.discardEnd); +} + +CC_BACKEND_END diff --git a/cocos/renderer/backend/RenderPassDescriptor.h b/cocos/renderer/backend/RenderPassParams.h similarity index 65% rename from cocos/renderer/backend/RenderPassDescriptor.h rename to cocos/renderer/backend/RenderPassParams.h index 67396c763a..8be949fee6 100644 --- a/cocos/renderer/backend/RenderPassDescriptor.h +++ b/cocos/renderer/backend/RenderPassParams.h @@ -38,28 +38,43 @@ class TextureBackend; * @{ */ +struct RenderPassFlags { + /** + * bitmask indicating which buffers to clear at the beginning of a render pass. + * This implies discard. + */ + TargetBufferFlags clear; + + /** + * bitmask indicating which buffers to discard at the beginning of a render pass. + * Discarded buffers have uninitialized content, they must be entirely drawn over or cleared. + */ + TargetBufferFlags discardStart; + + /** + * bitmask indicating which buffers to discard at the end of a render pass. + * Discarded buffers' content becomes invalid, they must not be read from again. + */ + TargetBufferFlags discardEnd; +}; + + /** * Store values about color, depth and stencil attachment. */ -struct RenderPassDescriptor +struct RenderPassParams { - RenderPassDescriptor& operator=(const RenderPassDescriptor& descriptor); - bool operator==(const RenderPassDescriptor& descriptor) const; - bool needDepthStencilAttachment() const { return depthTestEnabled || stencilTestEnabled; } + RenderPassParams& operator=(const RenderPassParams& descriptor) = default; + bool operator==(const RenderPassParams& descriptor) const; float clearDepthValue = 0.f; float clearStencilValue = 0.f; std::array clearColorValue {{0.f, 0.f, 0.f, 0.f}}; // double-braces required in C++11 - bool needColorAttachment = true; - bool depthTestEnabled = false; - bool stencilTestEnabled = false; - bool needClearColor = false; - bool needClearDepth = false; - bool needClearStencil = false; - TextureBackend* depthAttachmentTexture = nullptr; - TextureBackend* stencilAttachmentTexture = nullptr; - TextureBackend* colorAttachmentsTexture[MAX_COLOR_ATTCHMENT] = { nullptr }; + + // Now, only clear flag used + RenderPassFlags flags{}; }; +typedef RenderPassParams RenderPassParams; //end of _backend group /// @} diff --git a/cocos/renderer/backend/RenderPipeline.h b/cocos/renderer/backend/RenderPipeline.h index 69bab64d11..573526f37d 100644 --- a/cocos/renderer/backend/RenderPipeline.h +++ b/cocos/renderer/backend/RenderPipeline.h @@ -28,13 +28,14 @@ #include "Types.h" #include "base/CCRef.h" #include "renderer/CCPipelineDescriptor.h" -#include "renderer/backend/RenderPassDescriptor.h" +#include "renderer/backend/RenderPassParams.h" CC_BACKEND_BEGIN /** * @addtogroup _backend * @{ */ +class RenderTarget; /** * Render pipeline @@ -42,7 +43,7 @@ CC_BACKEND_BEGIN class RenderPipeline : public cocos2d::Ref { public: - virtual void update(const PipelineDescriptor & pipelineDescirptor, const RenderPassDescriptor& renderpassDescriptor) = 0; + virtual void update(const PipelineDescriptor & pipelineDescirptor, const RenderTarget* renderTarget, const RenderPassParams& renderPassParams) = 0; protected: virtual ~RenderPipeline() = default; diff --git a/cocos/renderer/backend/RenderTarget.h b/cocos/renderer/backend/RenderTarget.h new file mode 100644 index 0000000000..3dddbba88d --- /dev/null +++ b/cocos/renderer/backend/RenderTarget.h @@ -0,0 +1,72 @@ +#pragma once + +#include "base/CCRef.h" +#include "Texture.h" +#include + +CC_BACKEND_BEGIN + +class RenderTarget : public cocos2d::Ref { +public: + struct RenderBuffer { + TextureBackend* texture = nullptr; + uint8_t level = 0; // level when attached to a texture + explicit operator bool() const { + return texture != nullptr; + } + }; + typedef RenderBuffer ColorAttachment[MAX_COLOR_ATTCHMENT]; + + RenderTarget(bool defaultRenderTarget) : _defaultRenderTarget(defaultRenderTarget) {} + virtual ~RenderTarget() + { + for (auto colorItem : _color) + CC_SAFE_RELEASE(colorItem.texture); + CC_SAFE_RELEASE(_depth.texture); + CC_SAFE_RELEASE(_stencil.texture); + } + void setTargetFlags(TargetBufferFlags flags) { _flags = flags; } + TargetBufferFlags getTargetFlags() const { return _flags; } + void modifyTargetFlags(TargetBufferFlags flagsToAdd, TargetBufferFlags flagsToRemove) + { + _flags |= flagsToAdd; + _flags &= ~flagsToRemove; + } + + virtual void bindFrameBuffer() const {}; + virtual void unbindFrameBuffer() const {}; + + virtual void setColorAttachment(ColorAttachment attachment) { + for (auto colorItem : _color) + CC_SAFE_RELEASE(colorItem.texture); + memcpy(_color, attachment, sizeof(ColorAttachment)); + for (auto colorItem : _color) + CC_SAFE_RETAIN(colorItem.texture); + }; + virtual void setDepthAttachment(TextureBackend* attachment, int level = 0) + { + CC_SAFE_RELEASE(_depth.texture); + _depth.texture = attachment; + _depth.level = level; + CC_SAFE_RETAIN(_depth.texture); + }; + virtual void setStencilAttachment(TextureBackend* attachment, int level = 0) { + CC_SAFE_RELEASE(_stencil.texture); + _stencil.texture = attachment; + _stencil.level = level; + CC_SAFE_RETAIN(_stencil.texture); + }; + + bool isDefaultRenderTarget() const { return _defaultRenderTarget; } + + bool _defaultRenderTarget = false; + ColorAttachment _color{}; + RenderBuffer _depth{}; + RenderBuffer _stencil{}; + TargetBufferFlags _flags{}; + + // uint8_t samples = 1; + +}; + +CC_BACKEND_END diff --git a/cocos/renderer/backend/Texture.h b/cocos/renderer/backend/Texture.h index 47d0909917..d39b02e91c 100644 --- a/cocos/renderer/backend/Texture.h +++ b/cocos/renderer/backend/Texture.h @@ -51,14 +51,11 @@ struct TextureDescriptor SamplerDescriptor samplerDescriptor; }; -struct UtilsGL; - /** * A base texture */ class TextureBackend : public Ref { - friend struct UtilsGL; public: /** * Update sampler @@ -106,6 +103,8 @@ public: int getWidth() const { return _width; } int getHeight() const { return _height; } + int getBytesPerRow() const { return _width * _bitsPerElement / 8; } + protected: /** * @param descriptor Specifies the texture descirptor. diff --git a/cocos/renderer/backend/Types.h b/cocos/renderer/backend/Types.h index 77a82bfaa8..c0b2b9ecc1 100644 --- a/cocos/renderer/backend/Types.h +++ b/cocos/renderer/backend/Types.h @@ -27,6 +27,7 @@ #include "Macros.h" +#include #include #include #include "base/bitmask.h" @@ -258,6 +259,33 @@ enum class ColorWriteMask : uint32_t CC_ENABLE_BITMASK_OPS(ColorWriteMask) CC_ENABLE_BITSHIFT_OPS(ColorWriteMask) + +/** + * Bitmask for selecting render buffers + */ +enum class TargetBufferFlags : uint8_t { + NONE = 0x0u, //!< No buffer selected. + COLOR0 = 0x1u, //!< Color buffer selected. + COLOR1 = 0x2u, //!< Color buffer selected. + COLOR2 = 0x4u, //!< Color buffer selected. + COLOR3 = 0x8u, //!< Color buffer selected. + COLOR = COLOR0, //!< \deprecated + COLOR_ALL = COLOR0 | COLOR1 | COLOR2 | COLOR3, + DEPTH = 0x10u, //!< Depth buffer selected. + STENCIL = 0x20u, //!< Stencil buffer selected. + DEPTH_AND_STENCIL = DEPTH | STENCIL, //!< depth and stencil buffer selected. + ALL = COLOR_ALL | DEPTH | STENCIL //!< Color, depth and stencil buffer selected. +}; +CC_ENABLE_BITMASK_OPS(TargetBufferFlags) + +inline TargetBufferFlags getMRTColorFlag(size_t index) noexcept { + assert(index < 4); + return TargetBufferFlags(1u << index); +} + +typedef TargetBufferFlags ClearFlag; +typedef TargetBufferFlags RenderTargetFlag; + struct SamplerDescriptor { SamplerFilter magFilter = SamplerFilter::LINEAR; @@ -418,4 +446,6 @@ struct BlendDescriptor BlendFactor sourceAlphaBlendFactor = BlendFactor::ONE; BlendFactor destinationAlphaBlendFactor = BlendFactor::ZERO; }; + + CC_BACKEND_END diff --git a/cocos/renderer/backend/metal/CommandBufferMTL.h b/cocos/renderer/backend/metal/CommandBufferMTL.h index f677f64d42..62eadb0b42 100644 --- a/cocos/renderer/backend/metal/CommandBufferMTL.h +++ b/cocos/renderer/backend/metal/CommandBufferMTL.h @@ -61,11 +61,11 @@ public: virtual void beginFrame() override; /** - * Create a MTLRenderCommandEncoder object for graphics rendering to an attachment in a RenderPassDescriptor. - * MTLRenderCommandEncoder is cached if current RenderPassDescriptor is identical to previous one. + * Create a MTLRenderCommandEncoder object for graphics rendering to an attachment in a RenderPassParams. + * MTLRenderCommandEncoder is cached if current RenderPassParams is identical to previous one. * @param descriptor Specifies a group of render targets that hold the results of a render pass. */ - virtual void beginRenderPass(const RenderPassDescriptor& descriptor) override; + virtual void beginRenderPass(const RenderTarget* renderTarget, const RenderPassParams& descriptor) override; /** * Sets the current render pipeline state object. @@ -166,10 +166,22 @@ public: virtual void setDepthStencilState(DepthStencilState* depthStencilState) override; /** - * Get a screen snapshot - * @param callback A callback to deal with screen snapshot image. + * Read pixels from RenderTarget + * @param callback A callback to deal with pixel data read. */ - virtual void capture(TextureBackend* texture, std::function callback) override; + virtual void readPixels(RenderTarget* rt, std::function callback) override; + +protected: + /** + * Read a block of pixels from the given texture + * @param texture Specifies the texture to get the image. + * @param origX,origY Specify the window coordinates of the first pixel that is read from the given texture. This location is the lower left corner of a rectangular block of pixels. + * @param rectWidth,rectHeight Specify the dimensions of the pixel rectangle. rectWidth and rectHeight of one correspond to a single pixel. + * @param pbd, the output buffer for fill texels data + * @remark: !!!this function only can call after endFrame, then it's could be works well. + */ + static void readPixels(TextureBackend* texture, std::size_t origX, std::size_t origY, std::size_t rectWidth, std::size_t rectHeight, PixelBufferDescriptor& pbd); + static void readPixels(id texture, std::size_t origX, std::size_t origY, std::size_t rectWidth, std::size_t rectHeight, PixelBufferDescriptor& pbd); private: void prepareDrawing() const; @@ -179,7 +191,7 @@ private: void afterDraw(); void flush(); void flushCaptureCommands(); - id getRenderCommandEncoder(const RenderPassDescriptor& renderPassDescriptor); + id getRenderCommandEncoder(const RenderTarget* renderTarget, const RenderPassParams& renderPassParams); id _mtlCommandBuffer = nil; id _mtlCommandQueue = nil; @@ -195,7 +207,8 @@ private: unsigned int _renderTargetHeight = 0; dispatch_semaphore_t _frameBoundarySemaphore; - RenderPassDescriptor _prevRenderPassDescriptor; + const RenderTarget* _currentRenderTarget = nil; // weak ref + RenderPassParams _currentRenderPassParams; NSAutoreleasePool* _autoReleasePool = nil; std::vector>> _captureCallbacks; diff --git a/cocos/renderer/backend/metal/CommandBufferMTL.mm b/cocos/renderer/backend/metal/CommandBufferMTL.mm index 41eaff37a3..b8b8f43f29 100644 --- a/cocos/renderer/backend/metal/CommandBufferMTL.mm +++ b/cocos/renderer/backend/metal/CommandBufferMTL.mm @@ -32,12 +32,46 @@ #include "../Macros.h" #include "BufferManager.h" #include "DepthStencilStateMTL.h" +#include "RenderTargetMTL.h" CC_BACKEND_BEGIN namespace { - MTLWinding toMTLWinding(Winding winding) + +#define byte(n) ((n) * 8) +#define bit(n) (n) + static uint8_t getBitsPerElementMTL(MTLPixelFormat pixleFormat) + { + switch (pixleFormat) + { + case MTLPixelFormatDepth32Float_Stencil8: + return byte(8); + case MTLPixelFormatBGRA8Unorm: + case MTLPixelFormatRGBA8Unorm: + case MTLPixelFormatDepth32Float: + return byte(4); + #if (CC_TARGET_PLATFORM == CC_PLATFORM_MAC) + case MTLPixelFormatDepth24Unorm_Stencil8: + return byte(4); + #else + case MTLPixelFormatABGR4Unorm: + case MTLPixelFormatBGR5A1Unorm: + case MTLPixelFormatB5G6R5Unorm: + case MTLPixelFormatA1BGR5Unorm: + return byte(2); + #endif + case MTLPixelFormatA8Unorm: + case MTLPixelFormatR8Unorm: + return byte(1); + default: + assert(false); + break; + } + return 0; + } + + static MTLWinding toMTLWinding(Winding winding) { if (Winding::CLOCK_WISE == winding) return MTLWindingClockwise; @@ -45,7 +79,7 @@ namespace return MTLWindingCounterClockwise; } - MTLPrimitiveType toMTLPrimitive(PrimitiveType primitiveType) + static MTLPrimitiveType toMTLPrimitive(PrimitiveType primitiveType) { MTLPrimitiveType ret = MTLPrimitiveTypeTriangle; switch (primitiveType) @@ -71,7 +105,7 @@ namespace return ret; } - MTLIndexType toMTLIndexType(IndexFormat indexFormat) + static MTLIndexType toMTLIndexType(IndexFormat indexFormat) { if (IndexFormat::U_SHORT == indexFormat) return MTLIndexTypeUInt16; @@ -79,7 +113,7 @@ namespace return MTLIndexTypeUInt32; } - MTLCullMode toMTLCullMode(CullMode mode) + static MTLCullMode toMTLCullMode(CullMode mode) { switch (mode) { case CullMode::NONE: @@ -91,109 +125,21 @@ namespace } } - MTLRenderPassDescriptor* toMTLRenderPassDescriptor(const RenderPassDescriptor& descriptor) + static MTLRenderPassDescriptor* toMTLRenderPassDescriptor(const RenderTarget* rt, const RenderPassParams& params) { MTLRenderPassDescriptor* mtlDescritpor = [MTLRenderPassDescriptor renderPassDescriptor]; - // Set color attachments. - if (descriptor.needColorAttachment) - { - bool hasCustomColorAttachment = false; - for (int i = 0; i < MAX_COLOR_ATTCHMENT; ++i) - { - if (! descriptor.colorAttachmentsTexture[i]) - continue; - - mtlDescritpor.colorAttachments[i].texture = static_cast(descriptor.colorAttachmentsTexture[i])->getMTLTexture(); - if (descriptor.needClearColor) - { - mtlDescritpor.colorAttachments[i].loadAction = MTLLoadActionClear; - mtlDescritpor.colorAttachments[i].clearColor = MTLClearColorMake(descriptor.clearColorValue[0], - descriptor.clearColorValue[1], - descriptor.clearColorValue[2], - descriptor.clearColorValue[3]); - } - else - mtlDescritpor.colorAttachments[i].loadAction = MTLLoadActionLoad; - - hasCustomColorAttachment = true; - } - - if (!hasCustomColorAttachment) - { - mtlDescritpor.colorAttachments[0].texture = DeviceMTL::getCurrentDrawable().texture; - if (descriptor.needClearColor) - { - mtlDescritpor.colorAttachments[0].loadAction = MTLLoadActionClear; - mtlDescritpor.colorAttachments[0].clearColor = MTLClearColorMake(descriptor.clearColorValue[0], - descriptor.clearColorValue[1], - descriptor.clearColorValue[2], - descriptor.clearColorValue[3]); - } - else - mtlDescritpor.colorAttachments[0].loadAction = MTLLoadActionLoad; - } - - mtlDescritpor.colorAttachments[0].storeAction = MTLStoreActionStore; - } - - if(descriptor.needDepthStencilAttachment()) - { - // Set depth attachment - { - if (descriptor.depthAttachmentTexture) - mtlDescritpor.depthAttachment.texture = static_cast(descriptor.depthAttachmentTexture)->getMTLTexture(); - else - mtlDescritpor.depthAttachment.texture = UtilsMTL::getDefaultDepthStencilTexture(); - - if (descriptor.needClearDepth) - { - mtlDescritpor.depthAttachment.loadAction = MTLLoadActionClear; - mtlDescritpor.depthAttachment.clearDepth = descriptor.clearDepthValue; - } - else - mtlDescritpor.depthAttachment.loadAction = MTLLoadActionLoad; - - mtlDescritpor.depthAttachment.storeAction = MTLStoreActionStore; - } - - // Set stencil attachment - { - if (descriptor.stencilAttachmentTexture) - mtlDescritpor.stencilAttachment.texture = static_cast(descriptor.stencilAttachmentTexture)->getMTLTexture(); - else - mtlDescritpor.stencilAttachment.texture = UtilsMTL::getDefaultDepthStencilTexture(); - - if (descriptor.needClearStencil) - { - mtlDescritpor.stencilAttachment.loadAction = MTLLoadActionClear; - mtlDescritpor.stencilAttachment.clearStencil = descriptor.clearStencilValue; - } - else - mtlDescritpor.stencilAttachment.loadAction = MTLLoadActionLoad; - - mtlDescritpor.stencilAttachment.storeAction = MTLStoreActionStore; - } - } - + auto rtMTL = static_cast(rt); + rtMTL->applyRenderPassAttachments(params, mtlDescritpor); return mtlDescritpor; } - id getMTLTexture(TextureBackend* texture, int index = 0) + static id getMTLTexture(TextureBackend* texture, int index) { - switch (texture->getTextureType()) - { - case TextureType::TEXTURE_2D: - return static_cast(texture)->getMTLTexture(index); - case TextureType::TEXTURE_CUBE: - return static_cast(texture)->getMTLTexture(index); - default: - assert(false); - return nil; - } + return reinterpret_cast>(texture->getHandler(index)); } - id getMTLSamplerState(TextureBackend* texture) + static id getMTLSamplerState(TextureBackend* texture) { switch (texture->getTextureType()) { @@ -242,15 +188,16 @@ void CommandBufferMTL::beginFrame() BufferManager::beginFrame(); } -id CommandBufferMTL::getRenderCommandEncoder(const RenderPassDescriptor& renderPassDescriptor) +id CommandBufferMTL::getRenderCommandEncoder(const RenderTarget* renderTarget, const RenderPassParams& renderPassParams) { - if(_mtlRenderEncoder != nil && _prevRenderPassDescriptor == renderPassDescriptor) + if(_mtlRenderEncoder != nil && _currentRenderPassParams == renderPassParams && _currentRenderTarget == renderTarget) { return _mtlRenderEncoder; } else { - _prevRenderPassDescriptor = renderPassDescriptor; + _currentRenderTarget = renderTarget; + _currentRenderPassParams = renderPassParams; } if(_mtlRenderEncoder != nil) @@ -260,7 +207,7 @@ id CommandBufferMTL::getRenderCommandEncoder(const Rend _mtlRenderEncoder = nil; } - auto mtlDescriptor = toMTLRenderPassDescriptor(renderPassDescriptor); + auto mtlDescriptor = toMTLRenderPassDescriptor(renderTarget, renderPassParams); _renderTargetWidth = (unsigned int)mtlDescriptor.colorAttachments[0].texture.width; _renderTargetHeight = (unsigned int)mtlDescriptor.colorAttachments[0].texture.height; id mtlRenderEncoder = [_mtlCommandBuffer renderCommandEncoderWithDescriptor:mtlDescriptor]; @@ -269,9 +216,9 @@ id CommandBufferMTL::getRenderCommandEncoder(const Rend return mtlRenderEncoder; } -void CommandBufferMTL::beginRenderPass(const RenderPassDescriptor& descriptor) +void CommandBufferMTL::beginRenderPass(const RenderTarget* renderTarget, const RenderPassParams& descriptor) { - _mtlRenderEncoder = getRenderCommandEncoder(descriptor); + _mtlRenderEncoder = getRenderCommandEncoder(renderTarget, descriptor); // [_mtlRenderEncoder setFrontFacingWinding:MTLWindingCounterClockwise]; } @@ -355,8 +302,13 @@ void CommandBufferMTL::endRenderPass() } -void CommandBufferMTL::capture(TextureBackend* texture, std::function callback) +void CommandBufferMTL::readPixels(RenderTarget* rt, std::function callback) { + auto rtMTL = static_cast(rt); + + // we only read form color attachment 0 + // if it's nullptr, will regard as screen to perform capture + auto texture = rtMTL->_color[0].texture; CC_SAFE_RETAIN(texture); _captureCallbacks.emplace_back(texture, std::move(callback)); } @@ -407,7 +359,7 @@ void CommandBufferMTL::flushCaptureCommands() for(auto& cb : _captureCallbacks) { if(cb.first == nil) { // screen capture if(!screenPixelData) { - UtilsMTL::readPixels(_drawableTexture, 0, 0, [_drawableTexture width], [_drawableTexture height], screenPixelData); + CommandBufferMTL::readPixels(_drawableTexture, 0, 0, [_drawableTexture width], [_drawableTexture height], screenPixelData); // screen framebuffer copied, restore screen framebuffer only to true backend::Device::getInstance()->setFrameBufferOnly(true); } @@ -417,7 +369,7 @@ void CommandBufferMTL::flushCaptureCommands() PixelBufferDescriptor pixelData; auto texture = cb.first; assert(texture != nullptr); - UtilsMTL::readPixels(texture, 0, 0, texture->getWidth(), texture->getHeight(), pixelData); + CommandBufferMTL::readPixels(texture, 0, 0, texture->getWidth(), texture->getHeight(), pixelData); CC_SAFE_RELEASE(texture); cb.second(pixelData); } @@ -570,5 +522,52 @@ void CommandBufferMTL::setScissorRect(bool isEnabled, float x, float y, float wi [_mtlRenderEncoder setScissorRect:scissorRect]; } +void CommandBufferMTL::readPixels(TextureBackend* texture, std::size_t origX, std::size_t origY, std::size_t rectWidth, std::size_t rectHeight, PixelBufferDescriptor& pbd) +{ + CommandBufferMTL::readPixels(reinterpret_cast>(texture->getHandler()), origX, origY, rectWidth, rectHeight, pbd); +} + +void CommandBufferMTL::readPixels(id texture, std::size_t origX, std::size_t origY, std::size_t rectWidth, std::size_t rectHeight, PixelBufferDescriptor& pbd) +{ + NSUInteger texWidth = texture.width; + NSUInteger texHeight = texture.height; + MTLRegion region = MTLRegionMake2D(0, 0, texWidth, texHeight); + MTLRegion imageRegion = MTLRegionMake2D(origX, origY, rectWidth, rectHeight); + + MTLTextureDescriptor* textureDescriptor = + [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:[texture pixelFormat] + width:texWidth + height:texHeight + mipmapped:NO]; + id device = static_cast(DeviceMTL::getInstance())->getMTLDevice(); + id readPixelsTexture = [device newTextureWithDescriptor:textureDescriptor]; + + id commandQueue = static_cast(DeviceMTL::getInstance())->getMTLCommandQueue(); + auto commandBuffer = [commandQueue commandBuffer]; + // [commandBuffer enqueue]; + + id blitCommandEncoder = [commandBuffer blitCommandEncoder]; + [blitCommandEncoder copyFromTexture:texture sourceSlice:0 sourceLevel:0 sourceOrigin:region.origin sourceSize:region.size toTexture:readPixelsTexture destinationSlice:0 destinationLevel:0 destinationOrigin:region.origin]; + +#if (CC_TARGET_PLATFORM == CC_PLATFORM_MAC) + [blitCommandEncoder synchronizeResource:readPixelsTexture]; +#endif + [blitCommandEncoder endEncoding]; + + [commandBuffer addCompletedHandler:^(id commandBufferMTL) { + auto bytePerRow = rectWidth * getBitsPerElementMTL(texture.pixelFormat) / 8; + auto texelData = pbd._data.resize(bytePerRow * rectHeight); + if(texelData != nullptr) + { + [readPixelsTexture getBytes:texelData bytesPerRow:bytePerRow fromRegion:imageRegion mipmapLevel:0]; + UtilsMTL::swizzleImage(texelData, rectWidth, rectHeight, readPixelsTexture.pixelFormat); + pbd._width = rectWidth; + pbd._height = rectHeight; + } + [readPixelsTexture release]; + }]; + [commandBuffer commit]; + [commandBuffer waitUntilCompleted]; +} CC_BACKEND_END diff --git a/cocos/renderer/backend/metal/DeviceMTL.h b/cocos/renderer/backend/metal/DeviceMTL.h index 89622fd7b7..08fe84215d 100644 --- a/cocos/renderer/backend/metal/DeviceMTL.h +++ b/cocos/renderer/backend/metal/DeviceMTL.h @@ -95,6 +95,12 @@ public: * @return A TextureBackend object. */ virtual TextureBackend* newTexture(const TextureDescriptor& descriptor) override; + + RenderTarget* newDefaultRenderTarget(TargetBufferFlags rtf) override; + RenderTarget* newRenderTarget(TargetBufferFlags rtf, + TextureBackend* colorAttachment, + TextureBackend* depthAttachment, + TextureBackend* stencilAttachhment) override; /** * Create a DepthStencilState object. diff --git a/cocos/renderer/backend/metal/DeviceMTL.mm b/cocos/renderer/backend/metal/DeviceMTL.mm index 44d5cbfb99..fb61208947 100644 --- a/cocos/renderer/backend/metal/DeviceMTL.mm +++ b/cocos/renderer/backend/metal/DeviceMTL.mm @@ -31,6 +31,7 @@ #include "TextureMTL.h" #include "ProgramMTL.h" #include "DeviceInfoMTL.h" +#include "RenderTargetMTL.h" #include "base/ccMacros.h" @@ -108,6 +109,27 @@ TextureBackend* DeviceMTL::newTexture(const TextureDescriptor& descriptor) } } +RenderTarget* DeviceMTL::newDefaultRenderTarget(TargetBufferFlags rtf) +{ + auto rtGL = new RenderTargetMTL(true); + rtGL->setTargetFlags(rtf); + return rtGL; +} + +RenderTarget* DeviceMTL::newRenderTarget(TargetBufferFlags rtf, + TextureBackend* colorAttachment, + TextureBackend* depthAttachment, + TextureBackend* stencilAttachhment) +{ + auto rtGL = new RenderTargetMTL(false); + rtGL->setTargetFlags(rtf); + rtGL->bindFrameBuffer(); + rtGL->setColorAttachment(RenderTarget::ColorAttachment{ { colorAttachment, 0 } }); + rtGL->setDepthAttachment(depthAttachment); + rtGL->setStencilAttachment(stencilAttachhment); + return rtGL; +} + ShaderModule* DeviceMTL::newShaderModule(ShaderStage stage, const std::string& source) { return new (std::nothrow) ShaderModuleMTL(_mtlDevice, stage, source); diff --git a/cocos/renderer/backend/metal/RenderPipelineMTL.h b/cocos/renderer/backend/metal/RenderPipelineMTL.h index 323afd5f91..74b662db78 100644 --- a/cocos/renderer/backend/metal/RenderPipelineMTL.h +++ b/cocos/renderer/backend/metal/RenderPipelineMTL.h @@ -49,7 +49,7 @@ public: */ RenderPipelineMTL(id mtlDevice); ~RenderPipelineMTL(); - virtual void update(const PipelineDescriptor&, const RenderPassDescriptor&) override; + virtual void update(const PipelineDescriptor&, const RenderTarget* renderTarget, const RenderPassParams& renderPassParams) override; /** * Get a MTLRenderPipelineState object. @@ -61,14 +61,14 @@ private: void setVertexLayout(MTLRenderPipelineDescriptor*, const PipelineDescriptor&); void setBlendState(MTLRenderPipelineColorAttachmentDescriptor*, const BlendDescriptor&); void setShaderModules(const PipelineDescriptor&); - void setBlendStateAndFormat(const BlendDescriptor&, const RenderPassDescriptor&); - void getAttachmentFormat(const RenderPassDescriptor&, PixelFormat&, PixelFormat&, PixelFormat&); + void setBlendStateAndFormat(const BlendDescriptor&); + void getAttachmentFormat(const RenderTarget* renderTarget, const RenderPassParams& renderPassParams, PixelFormat colorAttachmentsFormat[MAX_COLOR_ATTCHMENT], PixelFormat&, PixelFormat&); id _mtlRenderPipelineState = nil; id _mtlDevice = nil; MTLRenderPipelineDescriptor* _mtlRenderPipelineDescriptor = nil; - PixelFormat _colorAttachmentsFormat[MAX_COLOR_ATTCHMENT] = { PixelFormat::DEFAULT }; + PixelFormat _colorAttachmentsFormat[MAX_COLOR_ATTCHMENT] = { PixelFormat::NONE }; PixelFormat _depthAttachmentFormat = PixelFormat::NONE; PixelFormat _stencilAttachmentFormat = PixelFormat::NONE; NSMutableDictionary* _mtlRenderPipelineStateCache = nil; diff --git a/cocos/renderer/backend/metal/RenderPipelineMTL.mm b/cocos/renderer/backend/metal/RenderPipelineMTL.mm index e092667b14..5514a477b4 100644 --- a/cocos/renderer/backend/metal/RenderPipelineMTL.mm +++ b/cocos/renderer/backend/metal/RenderPipelineMTL.mm @@ -24,6 +24,7 @@ #include "RenderPipelineMTL.h" #include "DeviceMTL.h" +#include "RenderTargetMTL.h" #include "ShaderModuleMTL.h" #include "DepthStencilStateMTL.h" #include "UtilsMTL.h" @@ -163,14 +164,15 @@ RenderPipelineMTL::RenderPipelineMTL(id mtlDevice) } void RenderPipelineMTL::update(const PipelineDescriptor & pipelineDescirptor, - const RenderPassDescriptor& renderPassDescriptor) + const RenderTarget* renderTarget, + const RenderPassParams& renderPassParams) { struct { size_t vertexShaderHash; size_t fragmentShaderHash; unsigned int vertexLayoutInfo[32]; - backend::PixelFormat colorAttachment; + backend::PixelFormat colorAttachment[MAX_COLOR_ATTCHMENT]; backend::PixelFormat depthAttachment; backend::PixelFormat stencilAttachment; bool blendEnabled; @@ -185,11 +187,11 @@ void RenderPipelineMTL::update(const PipelineDescriptor & pipelineDescirptor, memset(&hashMe, 0, sizeof(hashMe)); const auto& blendDescriptor = pipelineDescirptor.blendDescriptor; - getAttachmentFormat(renderPassDescriptor, _colorAttachmentsFormat[0], _depthAttachmentFormat, _stencilAttachmentFormat); + getAttachmentFormat(renderTarget, renderPassParams, _colorAttachmentsFormat, _depthAttachmentFormat, _stencilAttachmentFormat); auto program = static_cast(pipelineDescirptor.programState->getProgram()); hashMe.vertexShaderHash = program->getVertexShader()->getHashValue(); hashMe.fragmentShaderHash = program->getFragmentShader()->getHashValue(); - hashMe.colorAttachment = _colorAttachmentsFormat[0]; + memcpy(&hashMe.colorAttachment, &_colorAttachmentsFormat, sizeof(_colorAttachmentsFormat)); hashMe.depthAttachment = _depthAttachmentFormat; hashMe.stencilAttachment =_stencilAttachmentFormat; hashMe.blendEnabled = blendDescriptor.blendEnabled; @@ -232,7 +234,7 @@ void RenderPipelineMTL::update(const PipelineDescriptor & pipelineDescirptor, setShaderModules(pipelineDescirptor); setVertexLayout(_mtlRenderPipelineDescriptor, pipelineDescirptor); - setBlendStateAndFormat(pipelineDescirptor.blendDescriptor, renderPassDescriptor); + setBlendStateAndFormat(pipelineDescirptor.blendDescriptor); NSError *error = nil; _mtlRenderPipelineState = [_mtlDevice newRenderPipelineStateWithDescriptor:_mtlRenderPipelineDescriptor error:&error]; @@ -299,43 +301,29 @@ void RenderPipelineMTL::setShaderModules(const PipelineDescriptor& descriptor) _mtlRenderPipelineDescriptor.fragmentFunction = fragShaderModule->getMTLFunction(); } -void RenderPipelineMTL::getAttachmentFormat(const RenderPassDescriptor& descriptor, - PixelFormat& colorFormat, +void RenderPipelineMTL::getAttachmentFormat(const RenderTarget* renderTarget, + const RenderPassParams& params, + PixelFormat colorAttachmentsFormat[MAX_COLOR_ATTCHMENT], PixelFormat& depthFormat, PixelFormat& stencilFormat) { - if (descriptor.needColorAttachment) - { - // FIXME: now just handle color attachment 0. - if (descriptor.colorAttachmentsTexture[0]) - colorFormat = descriptor.colorAttachmentsTexture[0]->getTextureFormat(); + auto rtMTL = static_cast(renderTarget); + auto rtflags = rtMTL->getTargetFlags(); + for(auto i = 0; i < MAX_COLOR_ATTCHMENT; ++i) { + if (bitmask::any(rtflags, getMRTColorFlag(i))) + { + colorAttachmentsFormat[i] = rtMTL->getColorAttachmentPixelFormat(i); + } else - colorFormat = PixelFormat::DEFAULT; - } - else - { - colorFormat = PixelFormat::DEFAULT; + { + colorAttachmentsFormat[i] = PixelFormat::NONE; + } } - if (descriptor.needDepthStencilAttachment()) + if (bitmask::any(rtflags, RenderTargetFlag::DEPTH_AND_STENCIL)) { - if(descriptor.depthAttachmentTexture) - { - depthFormat = descriptor.depthAttachmentTexture->getTextureFormat(); - } - else - { - depthFormat = PixelFormat::D24S8; - } - - if (descriptor.stencilAttachmentTexture) - { - stencilFormat = descriptor.stencilAttachmentTexture->getTextureFormat(); - } - else - { - stencilFormat = PixelFormat::D24S8; - } + depthFormat = rtMTL->getDepthAttachmentPixelFormat(); + stencilFormat =rtMTL->getStencilAttachmentPixelFormat(); } else { @@ -343,13 +331,14 @@ void RenderPipelineMTL::getAttachmentFormat(const RenderPassDescriptor& descript } } -void RenderPipelineMTL::setBlendStateAndFormat(const BlendDescriptor& blendDescriptor, - const RenderPassDescriptor& renderPassDescriptor) +void RenderPipelineMTL::setBlendStateAndFormat(const BlendDescriptor& blendDescriptor) { for (int i = 0; i < MAX_COLOR_ATTCHMENT; ++i) { - if (PixelFormat::NONE == _colorAttachmentsFormat[i]) + if (PixelFormat::NONE == _colorAttachmentsFormat[i]) { + _mtlRenderPipelineDescriptor.colorAttachments[i].pixelFormat = MTLPixelFormat::MTLPixelFormatInvalid; continue; + } _mtlRenderPipelineDescriptor.colorAttachments[i].pixelFormat = UtilsMTL::toMTLPixelFormat(_colorAttachmentsFormat[i]); setBlendState(_mtlRenderPipelineDescriptor.colorAttachments[i], blendDescriptor); diff --git a/cocos/renderer/backend/metal/RenderTargetMTL.h b/cocos/renderer/backend/metal/RenderTargetMTL.h new file mode 100644 index 0000000000..51256c91ca --- /dev/null +++ b/cocos/renderer/backend/metal/RenderTargetMTL.h @@ -0,0 +1,48 @@ +#pragma once +#include "../RenderTarget.h" +#include "CommandBufferMTL.h" + +CC_BACKEND_BEGIN + +class RenderTargetMTL : public RenderTarget +{ +public: + struct Attachment { + id texture = nil; + int level = 0; + explicit operator bool() const { + return texture != nullptr; + } + }; + + /* + * generateFBO, false, use for screen framebuffer + */ + RenderTargetMTL(bool defaultRenderTarget); + ~RenderTargetMTL(); + + void bindFrameBuffer() const override; + void unbindFrameBuffer() const override; + + void setColorAttachment(ColorAttachment attachment) override; + void setDepthAttachment(TextureBackend* attachment, int level = 0) override; + void setStencilAttachment(TextureBackend* attachment, int level = 0) override; + + void applyRenderPassAttachments(const RenderPassParams& parmas, MTLRenderPassDescriptor* descriptor) const; + + Attachment getColorAttachment(int index) const; + Attachment getDepthAttachment() const; + Attachment getStencilAttachment() const; + + PixelFormat getColorAttachmentPixelFormat(int index) const; + PixelFormat getDepthAttachmentPixelFormat() const; + PixelFormat getStencilAttachmentPixelFormat() const; +public: + + // "Sidecar" textures used to implement automatic MSAA resolve. + // id multisampledColor[MRT::TARGET_COUNT] = { 0 }; + // id multisampledDepth = nil; + // MetalContext*, DeviceMTL* +}; + +CC_BACKEND_END diff --git a/cocos/renderer/backend/metal/RenderTargetMTL.mm b/cocos/renderer/backend/metal/RenderTargetMTL.mm new file mode 100644 index 0000000000..5c4d49dc70 --- /dev/null +++ b/cocos/renderer/backend/metal/RenderTargetMTL.mm @@ -0,0 +1,184 @@ +#include "RenderTargetMTL.h" +#include "UtilsMTL.h" + +CC_BACKEND_BEGIN + +static MTLLoadAction getLoadAction(const RenderPassParams& params, + TargetBufferFlags buffer) { + const auto clearFlags = (TargetBufferFlags) params.flags.clear; + const auto discardStartFlags = params.flags.discardStart; + if (bitmask::any(clearFlags, buffer)) { + return MTLLoadActionClear; + } else if (bitmask::any(discardStartFlags, buffer)) { + return MTLLoadActionDontCare; + } + return MTLLoadActionLoad; +} + +static MTLStoreAction getStoreAction(const RenderPassParams& params, + TargetBufferFlags buffer) { + const auto discardEndFlags = params.flags.discardEnd; + if (bitmask::any(discardEndFlags, buffer)) { + return MTLStoreActionDontCare; + } + return MTLStoreActionStore; +} + +RenderTargetMTL::RenderTargetMTL(bool defaultRenderTarget) : RenderTarget(defaultRenderTarget) +{ + +} +RenderTargetMTL::~RenderTargetMTL() +{ +} + +void RenderTargetMTL::bindFrameBuffer() const +{ +} + +void RenderTargetMTL::unbindFrameBuffer() const +{ +} +void RenderTargetMTL::setColorAttachment(ColorAttachment attachment) +{ + RenderTarget::setColorAttachment(attachment); + + +} + +void RenderTargetMTL::setDepthAttachment(TextureBackend* attachment, int level) +{ + RenderTarget::setDepthAttachment(attachment, level); + + +} + +void RenderTargetMTL::setStencilAttachment(TextureBackend* attachment, int level) +{ + RenderTarget::setStencilAttachment(attachment, level); + +} + +void RenderTargetMTL::applyRenderPassAttachments(const RenderPassParams& params, MTLRenderPassDescriptor* descriptor) const +{ + const auto discardFlags = params.flags.discardEnd; + + for (size_t i = 0; i < MAX_COLOR_ATTCHMENT; i++) { + auto attachment = getColorAttachment(i); + if (!attachment) { + continue; + } + + descriptor.colorAttachments[i].texture = attachment.texture; + descriptor.colorAttachments[i].level = attachment.level; + // descriptor.colorAttachments[i].slice = attachment.layer; + descriptor.colorAttachments[i].loadAction = getLoadAction(params, getMRTColorFlag(i)); + descriptor.colorAttachments[i].storeAction = getStoreAction(params, getMRTColorFlag(i)); + descriptor.colorAttachments[i].clearColor = MTLClearColorMake( + params.clearColorValue[0], params.clearColorValue[1], params.clearColorValue[2], params.clearColorValue[3]); +#if 0 + if (multisampledColor[i]) { + // We're rendering into our temporary MSAA texture and doing an automatic resolve. + // We should not be attempting to load anything into the MSAA texture. + assert(descriptor.colorAttachments[i].loadAction != MTLLoadActionLoad); + + descriptor.colorAttachments[i].texture = multisampledColor[i]; + descriptor.colorAttachments[i].level = 0; + descriptor.colorAttachments[i].slice = 0; + const bool discard = any(discardFlags & getMRTColorFlag(i)); + if (!discard) { + descriptor.colorAttachments[i].resolveTexture = attachment.texture; + descriptor.colorAttachments[i].resolveLevel = attachment.level; + descriptor.colorAttachments[i].resolveSlice = attachment.layer; + descriptor.colorAttachments[i].storeAction = MTLStoreActionMultisampleResolve; + } + } +#endif + } + + auto depthAttachment = getDepthAttachment(); + if(depthAttachment){ + descriptor.depthAttachment.texture = depthAttachment.texture; + descriptor.depthAttachment.level = depthAttachment.level; + // descriptor.depthAttachment.slice = depthAttachment.layer; + descriptor.depthAttachment.loadAction = getLoadAction(params, TargetBufferFlags::DEPTH); + descriptor.depthAttachment.storeAction = getStoreAction(params, TargetBufferFlags::DEPTH); + descriptor.depthAttachment.clearDepth = params.clearDepthValue; + } + + auto stencilAttachment = getStencilAttachment(); + if(stencilAttachment) { + descriptor.stencilAttachment.texture = stencilAttachment.texture; + descriptor.stencilAttachment.level = depthAttachment.level; + // descriptor.stencilAttachment.slice = depthAttachment.layer; + descriptor.stencilAttachment.loadAction = getLoadAction(params, TargetBufferFlags::STENCIL); + descriptor.stencilAttachment.storeAction = getStoreAction(params, TargetBufferFlags::STENCIL); + descriptor.stencilAttachment.clearStencil= params.clearStencilValue; + } +#if 0 + if (multisampledDepth) { + // We're rendering into our temporary MSAA texture and doing an automatic resolve. + // We should not be attempting to load anything into the MSAA texture. + assert(descriptor.depthAttachment.loadAction != MTLLoadActionLoad); + + descriptor.depthAttachment.texture = multisampledDepth; + descriptor.depthAttachment.level = 0; + descriptor.depthAttachment.slice = 0; + const bool discard = any(discardFlags & TargetBufferFlags::DEPTH); + if (!discard) { + descriptor.depthAttachment.resolveTexture = depthAttachment.texture; + descriptor.depthAttachment.resolveLevel = depthAttachment.level; + descriptor.depthAttachment.resolveSlice = depthAttachment.layer; + descriptor.depthAttachment.storeAction = MTLStoreActionMultisampleResolve; + } + } +#endif +} + +RenderTargetMTL::Attachment RenderTargetMTL::getColorAttachment(int index) const +{ + if(isDefaultRenderTarget() && index == 0) + return {DeviceMTL::getCurrentDrawable().texture, 0}; + auto& rb = this->_color[index]; + return RenderTargetMTL::Attachment{static_cast(rb) ? (id)(rb.texture->getHandler()) : nil, rb.level}; +} + +RenderTargetMTL::Attachment RenderTargetMTL::getDepthAttachment() const +{ + if(isDefaultRenderTarget()) + return {UtilsMTL::getDefaultDepthStencilTexture(), 0}; + auto& rb = this->_depth; + return RenderTargetMTL::Attachment{!!rb ? (id)(rb.texture->getHandler()) : nil, rb.level}; +} + +RenderTargetMTL::Attachment RenderTargetMTL::getStencilAttachment() const +{ + if(isDefaultRenderTarget()) + return {UtilsMTL::getDefaultDepthStencilTexture(), 0}; + auto& rb = this->_stencil; + return RenderTargetMTL::Attachment{!!rb ? (id)(rb.texture->getHandler()) : nil, rb.level}; +} + +PixelFormat RenderTargetMTL::getColorAttachmentPixelFormat(int index) const +{ + if(isDefaultRenderTarget() && index == 0) + return PixelFormat::DEFAULT; + auto& rb = this->_color[index]; + return rb ? rb.texture->getTextureFormat() : PixelFormat::NONE; +} + +PixelFormat RenderTargetMTL::getDepthAttachmentPixelFormat() const +{ // FIXME: egnx only support D24S8 + if(isDefaultRenderTarget() || !_depth) + return PixelFormat::D24S8; + return _depth.texture->getTextureFormat(); +} + +PixelFormat RenderTargetMTL::getStencilAttachmentPixelFormat() const +{ // FIXME: egnx only support D24S8 + if(isDefaultRenderTarget() || !_stencil) + return PixelFormat::D24S8; + return _stencil.texture->getTextureFormat(); +} + +CC_BACKEND_END diff --git a/cocos/renderer/backend/metal/TextureMTL.h b/cocos/renderer/backend/metal/TextureMTL.h index 685e5dc67b..f696fd78c3 100644 --- a/cocos/renderer/backend/metal/TextureMTL.h +++ b/cocos/renderer/backend/metal/TextureMTL.h @@ -147,10 +147,12 @@ public: int getCount() const override { return _textureInfo._maxIdx + 1; } /** - * Get MTLTexture object. + * Get MTLTexture object. reinterpret_cast>(handler); * @return A MTLTexture object. */ - inline id getMTLTexture(int index = 0) const { return _textureInfo._mtlTextures[index]; } + uintptr_t getHandler(int index = 0) const override { + return reinterpret_cast((void*)_textureInfo._mtlTextures[index]); + } /** * Get MTLSamplerState object @@ -201,13 +203,11 @@ public: virtual void updateTextureDescriptor(const cocos2d::backend::TextureDescriptor &descriptor, int index = 0) override; int getCount() const override { return _textureInfo._maxIdx + 1; } - - /** - * Get MTLTexture object. - * @return A MTLTexture object. - */ - inline id getMTLTexture(int index = 0) const { return _textureInfo._mtlTextures[index]; } + uintptr_t getHandler(int index = 0) const override { + return reinterpret_cast((void*)_textureInfo._mtlTextures[index]); + } + /** * Get MTLSamplerState object * @return A MTLSamplerState object. diff --git a/cocos/renderer/backend/metal/TextureMTL.mm b/cocos/renderer/backend/metal/TextureMTL.mm index ed9d089010..1a81c5e3f1 100644 --- a/cocos/renderer/backend/metal/TextureMTL.mm +++ b/cocos/renderer/backend/metal/TextureMTL.mm @@ -194,7 +194,8 @@ namespace return bytesPerRow; } - std::size_t getBytesPerRow(PixelFormat textureFormat, std::size_t width, std::size_t bitsPerElement) + // TODO: tidy APIs, compression pixelFormat and non-compression pixelFormat + std::size_t getBytesPerRowMTL(PixelFormat textureFormat, std::size_t width, std::size_t bitsPerElement) { MTLPixelFormat pixelFormat = UtilsMTL::toMTLPixelFormat(textureFormat); std::size_t bytesPerRow = 0; @@ -361,7 +362,7 @@ void TextureMTL::updateSubData(std::size_t xoffset, std::size_t yoffset, std::si width * height, _textureFormat, &convertedData); - std::size_t bytesPerRow = getBytesPerRow(_textureFormat, width, _bitsPerElement); + std::size_t bytesPerRow = getBytesPerRowMTL(_textureFormat, width, _bitsPerElement); [mtlTexture replaceRegion:region mipmapLevel:level @@ -393,7 +394,7 @@ void TextureMTL::generateMipmaps() if(!_hasMipmaps) { _hasMipmaps = true; - UtilsMTL::generateMipmaps(this->getMTLTexture()); + UtilsMTL::generateMipmaps(reinterpret_cast>(this->getHandler())); } } @@ -454,7 +455,7 @@ void TextureCubeMTL::generateMipmaps() if(!_hasMipmaps) { _hasMipmaps = true; - UtilsMTL::generateMipmaps(this->getMTLTexture()); + UtilsMTL::generateMipmaps(reinterpret_cast>(this->getHandler())); } } diff --git a/cocos/renderer/backend/metal/UtilsMTL.h b/cocos/renderer/backend/metal/UtilsMTL.h index bc9e6b0eee..16ebf39832 100644 --- a/cocos/renderer/backend/metal/UtilsMTL.h +++ b/cocos/renderer/backend/metal/UtilsMTL.h @@ -83,18 +83,7 @@ struct UtilsMTL * @param texture Specifies a texture to generate mipmap. */ static void generateMipmaps(id texture); - - /** - * Read a block of pixels from the given texture - * @param texture Specifies the texture to get the image. - * @param origX,origY Specify the window coordinates of the first pixel that is read from the given texture. This location is the lower left corner of a rectangular block of pixels. - * @param rectWidth,rectHeight Specify the dimensions of the pixel rectangle. rectWidth and rectHeight of one correspond to a single pixel. - * @param pbd, the output buffer for fill texels data - * @remark: !!!this function only can call after endFrame, then it's could be works well. - */ - static void readPixels(TextureBackend* texture, std::size_t origX, std::size_t origY, std::size_t rectWidth, std::size_t rectHeight, PixelBufferDescriptor& pbd); - static void readPixels(id texture, std::size_t origX, std::size_t origY, std::size_t rectWidth, std::size_t rectHeight, PixelBufferDescriptor& pbd); - + /** * Swizzle the iamge form the given format to MTLPixelFormatRGBA8Unorm. * @param image Specifies the image to be swizzled. diff --git a/cocos/renderer/backend/metal/UtilsMTL.mm b/cocos/renderer/backend/metal/UtilsMTL.mm index d17eabaebf..2a98b7d1ae 100644 --- a/cocos/renderer/backend/metal/UtilsMTL.mm +++ b/cocos/renderer/backend/metal/UtilsMTL.mm @@ -36,39 +36,6 @@ id UtilsMTL::_defaultColorAttachmentTexture = nil; id UtilsMTL::_defaultDepthStencilAttachmentTexture = nil; namespace { -#define byte(n) ((n) * 8) -#define bit(n) (n) - - uint8_t getBitsPerElement(MTLPixelFormat pixleFormat) - { - switch (pixleFormat) - { - case MTLPixelFormatDepth32Float_Stencil8: - return byte(8); - case MTLPixelFormatBGRA8Unorm: - case MTLPixelFormatRGBA8Unorm: - case MTLPixelFormatDepth32Float: - return byte(4); -#if (CC_TARGET_PLATFORM == CC_PLATFORM_MAC) - case MTLPixelFormatDepth24Unorm_Stencil8: - return byte(4); -#else - case MTLPixelFormatABGR4Unorm: - case MTLPixelFormatBGR5A1Unorm: - case MTLPixelFormatB5G6R5Unorm: - case MTLPixelFormatA1BGR5Unorm: - return byte(2); -#endif - case MTLPixelFormatA8Unorm: - case MTLPixelFormatR8Unorm: - return byte(1); - default: - assert(false); - break; - } - return 0; - } - MTLPixelFormat getSupportedDepthStencilFormat() { MTLPixelFormat pixelFormat = MTLPixelFormatDepth32Float_Stencil8; @@ -217,59 +184,4 @@ void UtilsMTL::swizzleImage(unsigned char *image, std::size_t width, std::size_t } } -void UtilsMTL::readPixels(TextureBackend* texture, std::size_t origX, std::size_t origY, std::size_t rectWidth, std::size_t rectHeight, PixelBufferDescriptor& pbd) -{ - switch(texture->getTextureType()){ - case TextureType::TEXTURE_2D: - UtilsMTL::readPixels(static_cast(texture)->getMTLTexture(), origX, origY, rectWidth, rectHeight, pbd); - break; - case TextureType::TEXTURE_CUBE: - UtilsMTL::readPixels(static_cast(texture)->getMTLTexture(), origX, origY, rectWidth, rectHeight, pbd); - break; - } -} - -void UtilsMTL::readPixels(id texture, std::size_t origX, std::size_t origY, std::size_t rectWidth, std::size_t rectHeight, PixelBufferDescriptor& pbd) -{ - NSUInteger texWidth = texture.width; - NSUInteger texHeight = texture.height; - MTLRegion region = MTLRegionMake2D(0, 0, texWidth, texHeight); - MTLRegion imageRegion = MTLRegionMake2D(origX, origY, rectWidth, rectHeight); - - MTLTextureDescriptor* textureDescriptor = - [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:[texture pixelFormat] - width:texWidth - height:texHeight - mipmapped:NO]; - id device = static_cast(DeviceMTL::getInstance())->getMTLDevice(); - id readPixelsTexture = [device newTextureWithDescriptor:textureDescriptor]; - - id commandQueue = static_cast(DeviceMTL::getInstance())->getMTLCommandQueue(); - auto commandBuffer = [commandQueue commandBuffer]; - // [commandBuffer enqueue]; - - id blitCommandEncoder = [commandBuffer blitCommandEncoder]; - [blitCommandEncoder copyFromTexture:texture sourceSlice:0 sourceLevel:0 sourceOrigin:region.origin sourceSize:region.size toTexture:readPixelsTexture destinationSlice:0 destinationLevel:0 destinationOrigin:region.origin]; - -#if (CC_TARGET_PLATFORM == CC_PLATFORM_MAC) - [blitCommandEncoder synchronizeResource:readPixelsTexture]; -#endif - [blitCommandEncoder endEncoding]; - - [commandBuffer addCompletedHandler:^(id commandBufferMTL) { - auto bytePerRow = rectWidth * getBitsPerElement(texture.pixelFormat) / 8; - auto texelData = pbd._data.resize(bytePerRow * rectHeight); - if(texelData != nullptr) - { - [readPixelsTexture getBytes:texelData bytesPerRow:bytePerRow fromRegion:imageRegion mipmapLevel:0]; - swizzleImage(texelData, rectWidth, rectHeight, readPixelsTexture.pixelFormat); - pbd._width = rectWidth; - pbd._height = rectHeight; - } - [readPixelsTexture release]; - }]; - [commandBuffer commit]; - [commandBuffer waitUntilCompleted]; -} - CC_BACKEND_END diff --git a/cocos/renderer/backend/opengl/CommandBufferGL.cpp b/cocos/renderer/backend/opengl/CommandBufferGL.cpp index 11137f25f0..e2c27a25e8 100644 --- a/cocos/renderer/backend/opengl/CommandBufferGL.cpp +++ b/cocos/renderer/backend/opengl/CommandBufferGL.cpp @@ -33,27 +33,13 @@ #include "base/CCEventType.h" #include "base/CCDirector.h" #include "renderer/backend/opengl/UtilsGL.h" +#include "RenderTargetGL.h" #include CC_BACKEND_BEGIN namespace { - - GLuint getHandler(TextureBackend *texture) - { - switch (texture->getTextureType()) - { - case TextureType::TEXTURE_2D: - return static_cast(texture)->getHandler(); - case TextureType::TEXTURE_CUBE: - return static_cast(texture)->getHandler(); - default: - assert(false); - return 0; - } - } - void applyTexture(TextureBackend* texture, int slot, int index) { switch (texture->getTextureType()) @@ -101,199 +87,66 @@ void CommandBufferGL::beginFrame() { } -void CommandBufferGL::beginRenderPass(const RenderPassDescriptor& descirptor) +void CommandBufferGL::beginRenderPass(const RenderTarget* rt, const RenderPassParams& descirptor) { - applyRenderPassDescriptor(descirptor); -} - -void CommandBufferGL::applyRenderPassDescriptor(const RenderPassDescriptor& descirptor) -{ - bool useColorAttachmentExternal = descirptor.needColorAttachment && descirptor.colorAttachmentsTexture[0]; - bool useDepthAttachmentExternal = descirptor.depthTestEnabled && descirptor.depthAttachmentTexture; - bool useStencilAttachmentExternal = descirptor.stencilTestEnabled && descirptor.stencilAttachmentTexture; - bool useGeneratedFBO = false; - if (useColorAttachmentExternal || useDepthAttachmentExternal || useStencilAttachmentExternal) - { - if(_generatedFBO == 0) - { - glGenFramebuffers(1, &_generatedFBO); - } - _currentFBO = _generatedFBO; - useGeneratedFBO = true; - } - else - { - _currentFBO = _defaultFBO; - } - glBindFramebuffer(GL_FRAMEBUFFER, _currentFBO); + auto rtGL = static_cast(rt); - if (useDepthAttachmentExternal) - { - glFramebufferTexture2D(GL_FRAMEBUFFER, - GL_DEPTH_ATTACHMENT, - GL_TEXTURE_2D, - getHandler(descirptor.depthAttachmentTexture), - 0); - CHECK_GL_ERROR_DEBUG(); + rtGL->bindFrameBuffer(); + + auto clearFlags = descirptor.flags.clear; - _generatedFBOBindDepth = true; - } - else - { - if (_generatedFBOBindDepth && useGeneratedFBO) - { - glFramebufferTexture2D(GL_FRAMEBUFFER, - GL_DEPTH_ATTACHMENT, - GL_TEXTURE_2D, - 0, - 0); - CHECK_GL_ERROR_DEBUG(); - - _generatedFBOBindDepth = false; - } - } - - if (useStencilAttachmentExternal) - { - glFramebufferTexture2D(GL_FRAMEBUFFER, - GL_STENCIL_ATTACHMENT, - GL_TEXTURE_2D, - getHandler(descirptor.stencilAttachmentTexture), - 0); - CHECK_GL_ERROR_DEBUG(); - - _generatedFBOBindStencil = true; - } - else - { - if (_generatedFBOBindStencil && useGeneratedFBO) - { - glFramebufferTexture2D(GL_FRAMEBUFFER, - GL_STENCIL_ATTACHMENT, - GL_TEXTURE_2D, - 0, - 0); - CHECK_GL_ERROR_DEBUG(); - - _generatedFBOBindStencil = false; - } - } - - if (descirptor.needColorAttachment) - { - int i = 0; - for (const auto& texture : descirptor.colorAttachmentsTexture) - { - if (texture) - { - // TODO: support texture cube - glFramebufferTexture2D(GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0 + i, - GL_TEXTURE_2D, - getHandler(texture), - 0); - } - CHECK_GL_ERROR_DEBUG(); - ++i; - } - - if (useGeneratedFBO) - _generatedFBOBindColor = true; - -#if CC_TARGET_PLATFORM == CC_PLATFORM_WIN32 || CC_TARGET_PLATFORM == CC_PLATFORM_LINUX - if (_framebufferReadWriteDisabled) - { - if (useGeneratedFBO) //user-defined framebuffer - { - glDrawBuffer(GL_COLOR_ATTACHMENT0); - glReadBuffer(GL_COLOR_ATTACHMENT0); - } - else //default framebuffer - { - glDrawBuffer(GL_BACK); - glReadBuffer(GL_BACK); - } - _framebufferReadWriteDisabled = false; - } -#endif - } - else - { - if (_generatedFBOBindColor && useGeneratedFBO) - { - // FIXME: Now only support attaching to attachment 0. - glFramebufferTexture2D(GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, - 0, - 0); - - _generatedFBOBindColor = false; - } - - // If not draw buffer is needed, should invoke this line explicitly, or it will cause - // GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER and GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER error. - // https://stackoverflow.com/questions/28313782/porting-opengl-es-framebuffer-to-opengl -#if CC_TARGET_PLATFORM == CC_PLATFORM_WIN32 || CC_TARGET_PLATFORM == CC_PLATFORM_LINUX - glDrawBuffer(GL_NONE); - glReadBuffer(GL_NONE); - _framebufferReadWriteDisabled = true; -#endif - } - CHECK_GL_ERROR_DEBUG(); - // set clear color, depth and stencil GLbitfield mask = 0; - if (descirptor.needClearColor) + if (bitmask::any(clearFlags, TargetBufferFlags::COLOR)) { mask |= GL_COLOR_BUFFER_BIT; const auto& clearColor = descirptor.clearColorValue; glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]); } - + CHECK_GL_ERROR_DEBUG(); - + GLboolean oldDepthWrite = GL_FALSE; GLboolean oldDepthTest = GL_FALSE; GLfloat oldDepthClearValue = 0.f; GLint oldDepthFunc = GL_LESS; - if (descirptor.needClearDepth) + if (bitmask::any(clearFlags, TargetBufferFlags::DEPTH)) { glGetBooleanv(GL_DEPTH_WRITEMASK, &oldDepthWrite); glGetBooleanv(GL_DEPTH_TEST, &oldDepthTest); glGetFloatv(GL_DEPTH_CLEAR_VALUE, &oldDepthClearValue); glGetIntegerv(GL_DEPTH_FUNC, &oldDepthFunc); - + mask |= GL_DEPTH_BUFFER_BIT; glClearDepth(descirptor.clearDepthValue); glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); glDepthFunc(GL_ALWAYS); } - + CHECK_GL_ERROR_DEBUG(); - - if (descirptor.needClearStencil) + + if (bitmask::any(clearFlags, TargetBufferFlags::STENCIL)) { mask |= GL_STENCIL_BUFFER_BIT; glClearStencil(descirptor.clearStencilValue); } - if(mask) glClear(mask); - + if (mask) glClear(mask); + CHECK_GL_ERROR_DEBUG(); - + // restore depth test - if (descirptor.needClearDepth) + if (bitmask::any(clearFlags, TargetBufferFlags::DEPTH)) { if (!oldDepthTest) glDisable(GL_DEPTH_TEST); - + glDepthMask(oldDepthWrite); glDepthFunc(oldDepthFunc); glClearDepth(oldDepthClearValue); } - + CHECK_GL_ERROR_DEBUG(); } @@ -379,7 +232,6 @@ void CommandBufferGL::endRenderPass() void CommandBufferGL::endFrame() { - // executeGpuCommandsCompleteOps(); } void CommandBufferGL::setDepthStencilState(DepthStencilState* depthStencilState) @@ -630,14 +482,64 @@ void CommandBufferGL::setScissorRect(bool isEnabled, float x, float y, float wid } } -void CommandBufferGL::capture(TextureBackend* texture, std::function callback) +void CommandBufferGL::readPixels(RenderTarget* rt, std::function callback) { PixelBufferDescriptor pbd; - if (!texture) - UtilsGL::readPixels(nullptr, _viewPort.x, _viewPort.y, _viewPort.w, _viewPort.h, pbd); - else - UtilsGL::readPixels(texture, 0, 0, texture->getWidth(), texture->getHeight(), pbd); + if(rt->isDefaultRenderTarget()) + { // read pixels from screen + readPixels(rt, _viewPort.x, _viewPort.y, _viewPort.w, _viewPort.h, _viewPort.w * 4, pbd); + } + else { + // we only readPixels from the COLOR0 attachment. + auto colorAttachment = rt->_color[0].texture; + if(colorAttachment) { + readPixels(rt, 0, 0, colorAttachment->getWidth(),colorAttachment->getHeight(), colorAttachment->getBytesPerRow(), pbd); + } + } callback(pbd); } +void CommandBufferGL::readPixels(RenderTarget* rt, int x, int y, uint32_t width, uint32_t height, uint32_t bytesPerRow, PixelBufferDescriptor& pbd) +{ + rt->bindFrameBuffer(); + + glPixelStorei(GL_PACK_ALIGNMENT, 1); + + auto bufferSize = bytesPerRow * height; +#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32 && defined(GL_ES_VERSION_3_0)) || \ + (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID && defined(GL_PIXEL_PACK_BUFFER)) + GLuint pbo; + glGenBuffers(1, &pbo); + glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo); + glBufferData(GL_PIXEL_PACK_BUFFER, bufferSize, nullptr, GL_STATIC_DRAW); + glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + auto buffer = (uint8_t*)glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, bufferSize, GL_MAP_READ_BIT); +#else + std::unique_ptr bufferStorage(new uint8_t[bufferSize]); + auto buffer = bufferStorage.get(); + memset(buffer, 0, bufferSize); + glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer); +#endif + uint8_t* wptr = nullptr; + if (buffer && (wptr = pbd._data.resize(bufferSize))) { + auto rptr = buffer + (height - 1) * bytesPerRow; + for (int row = 0; row < height; ++row) { + memcpy(wptr, rptr, bytesPerRow); + wptr += bytesPerRow; + rptr -= bytesPerRow; + } + pbd._width = width; + pbd._height = height; + } +#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32 && defined(GL_ES_VERSION_3_0)) || \ + (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID && defined(GL_PIXEL_PACK_BUFFER)) + glUnmapBuffer(GL_PIXEL_PACK_BUFFER); + glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); + glDeleteBuffers(1, &pbo); +#endif + + if (!rt->isDefaultRenderTarget()) + rt->unbindFrameBuffer(); +} + CC_BACKEND_END diff --git a/cocos/renderer/backend/opengl/CommandBufferGL.h b/cocos/renderer/backend/opengl/CommandBufferGL.h index c2f4e26d5e..a5a7b1353d 100644 --- a/cocos/renderer/backend/opengl/CommandBufferGL.h +++ b/cocos/renderer/backend/opengl/CommandBufferGL.h @@ -65,7 +65,7 @@ public: * Begin a render pass, initial color, depth and stencil attachment. * @param descriptor Specifies a group of render targets that hold the results of a render pass. */ - virtual void beginRenderPass(const RenderPassDescriptor& descriptor) override; + virtual void beginRenderPass(const RenderTarget* rt, const RenderPassParams& descriptor) override; /** * Sets the current render pipeline state object. @@ -167,7 +167,10 @@ public: * Get a screen snapshot * @param callback A callback to deal with screen snapshot image. */ - virtual void capture(TextureBackend* texture, std::function callback) override; + virtual void readPixels(RenderTarget* rt, std::function callback) override; + +protected: + void readPixels(RenderTarget* rt, int x, int y, uint32_t width, uint32_t height, uint32_t bytesPerRow, PixelBufferDescriptor& pbd); private: struct Viewport @@ -183,7 +186,6 @@ private: void setUniforms(ProgramGL* program) const; void setUniform(bool isArray, GLuint location, unsigned int size, GLenum uniformType, void* data) const; void cleanResources(); - void applyRenderPassDescriptor(const RenderPassDescriptor& descirptor); // The frame buffer generated by engine. All frame buffer other than default frame buffer share it. GLuint _generatedFBO = 0; diff --git a/cocos/renderer/backend/opengl/DeviceGL.cpp b/cocos/renderer/backend/opengl/DeviceGL.cpp index f4f2ede1e7..08123372d5 100644 --- a/cocos/renderer/backend/opengl/DeviceGL.cpp +++ b/cocos/renderer/backend/opengl/DeviceGL.cpp @@ -31,6 +31,7 @@ #include "DepthStencilStateGL.h" #include "ProgramGL.h" #include "DeviceInfoGL.h" +#include "RenderTargetGL.h" CC_BACKEND_BEGIN @@ -82,6 +83,27 @@ TextureBackend* DeviceGL::newTexture(const TextureDescriptor& descriptor) } } +RenderTarget* DeviceGL::newDefaultRenderTarget(TargetBufferFlags rtf) +{ + auto rtGL = new RenderTargetGL(true); + rtGL->setTargetFlags(rtf); + return rtGL; +} + +RenderTarget* DeviceGL::newRenderTarget(TargetBufferFlags rtf, + TextureBackend* colorAttachment, + TextureBackend* depthAttachment, + TextureBackend* stencilAttachhment) +{ + auto rtGL = new RenderTargetGL(false); + rtGL->setTargetFlags(rtf); + rtGL->bindFrameBuffer(); + rtGL->setColorAttachment({ RenderTarget::ColorAttachment{ {colorAttachment, 0} } }); + rtGL->setDepthAttachment(depthAttachment); + rtGL->setStencilAttachment(stencilAttachhment); + return rtGL; +} + ShaderModule* DeviceGL::newShaderModule(ShaderStage stage, const std::string& source) { return new (std::nothrow) ShaderModuleGL(stage, source); diff --git a/cocos/renderer/backend/opengl/DeviceGL.h b/cocos/renderer/backend/opengl/DeviceGL.h index 4ab0409577..0c155c9bf9 100644 --- a/cocos/renderer/backend/opengl/DeviceGL.h +++ b/cocos/renderer/backend/opengl/DeviceGL.h @@ -61,6 +61,12 @@ public: */ virtual TextureBackend* newTexture(const TextureDescriptor& descriptor) override; + RenderTarget* newDefaultRenderTarget(TargetBufferFlags rtf) override; + RenderTarget* newRenderTarget(TargetBufferFlags rtf, + TextureBackend* colorAttachment, + TextureBackend* depthAttachment, + TextureBackend* stencilAttachhment) override; + /** * Create an auto released DepthStencilState object. * @param descriptor Specifies depth and stencil description. diff --git a/cocos/renderer/backend/opengl/RenderPipelineGL.cpp b/cocos/renderer/backend/opengl/RenderPipelineGL.cpp index e458c8e3e9..0f9827866b 100644 --- a/cocos/renderer/backend/opengl/RenderPipelineGL.cpp +++ b/cocos/renderer/backend/opengl/RenderPipelineGL.cpp @@ -33,7 +33,7 @@ Copyright (c) 2020 c4games.com. CC_BACKEND_BEGIN -void RenderPipelineGL::update(const PipelineDescriptor& pipelineDescirptor, const RenderPassDescriptor& renderpassDescriptor) +void RenderPipelineGL::update(const PipelineDescriptor& pipelineDescirptor, const RenderTarget*, const RenderPassParams&) { if(_programGL != pipelineDescirptor.programState->getProgram()) { @@ -54,10 +54,10 @@ void RenderPipelineGL::updateBlendState(const BlendDescriptor& descriptor) auto destinationRGBBlendFactor = UtilsGL::toGLBlendFactor(descriptor.destinationRGBBlendFactor); auto sourceAlphaBlendFactor = UtilsGL::toGLBlendFactor(descriptor.sourceAlphaBlendFactor); auto destinationAlphaBlendFactor = UtilsGL::toGLBlendFactor(descriptor.destinationAlphaBlendFactor); - GLboolean writeMaskRed = _Bitmask_includes(descriptor.writeMask, ColorWriteMask::RED); - GLboolean writeMaskGreen = _Bitmask_includes(descriptor.writeMask, ColorWriteMask::GREEN); - GLboolean writeMaskBlue = _Bitmask_includes(descriptor.writeMask, ColorWriteMask::BLUE); - GLboolean writeMaskAlpha = _Bitmask_includes(descriptor.writeMask, ColorWriteMask::ALPHA); + GLboolean writeMaskRed = bitmask::any(descriptor.writeMask, ColorWriteMask::RED); + GLboolean writeMaskGreen = bitmask::any(descriptor.writeMask, ColorWriteMask::GREEN); + GLboolean writeMaskBlue = bitmask::any(descriptor.writeMask, ColorWriteMask::BLUE); + GLboolean writeMaskAlpha = bitmask::any(descriptor.writeMask, ColorWriteMask::ALPHA); if (blendEnabled) { diff --git a/cocos/renderer/backend/opengl/RenderPipelineGL.h b/cocos/renderer/backend/opengl/RenderPipelineGL.h index f7986dd70b..db22d8ca1f 100644 --- a/cocos/renderer/backend/opengl/RenderPipelineGL.h +++ b/cocos/renderer/backend/opengl/RenderPipelineGL.h @@ -51,7 +51,7 @@ public: RenderPipelineGL() = default; ~RenderPipelineGL(); - virtual void update(const PipelineDescriptor & pipelineDescirptor, const RenderPassDescriptor& renderpassDescriptor) override; + virtual void update(const PipelineDescriptor & pipelineDescirptor, const RenderTarget* renderTarget, const RenderPassParams& renderParams) override; /** * Get program instance. * @return Program instance. diff --git a/cocos/renderer/backend/opengl/RenderTargetGL.cpp b/cocos/renderer/backend/opengl/RenderTargetGL.cpp new file mode 100644 index 0000000000..00d3963abd --- /dev/null +++ b/cocos/renderer/backend/opengl/RenderTargetGL.cpp @@ -0,0 +1,109 @@ +#include "RenderTargetGL.h" +#include "base/ccMacros.h" + +CC_BACKEND_BEGIN + +RenderTargetGL::RenderTargetGL(bool defaultRenderTarget) : RenderTarget(defaultRenderTarget) +{ + if (!defaultRenderTarget) { + glGenFramebuffers(1, &_FBO); + } + else { + _FBO = 0; + } +} +RenderTargetGL::~RenderTargetGL() +{ + if (!_defaultRenderTarget) { + bindFrameBuffer(); + + for (auto slot = 0; slot < MAX_COLOR_ATTCHMENT; ++slot) + glFramebufferTexture2D(GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0 + slot, + GL_TEXTURE_2D, + 0, + 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, + GL_DEPTH_ATTACHMENT, + GL_TEXTURE_2D, + 0, + 0); + + glFramebufferTexture2D(GL_FRAMEBUFFER, + GL_STENCIL_ATTACHMENT, + GL_TEXTURE_2D, + 0, + 0); + + unbindFrameBuffer(); + glDeleteFramebuffers(1, &_FBO); + CHECK_GL_ERROR_DEBUG(); + } +} + +void RenderTargetGL::bindFrameBuffer() const +{ + glBindFramebuffer(GL_FRAMEBUFFER, _FBO); +} + +void RenderTargetGL::unbindFrameBuffer() const +{ + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + +void RenderTargetGL::setColorAttachment(ColorAttachment attachment) +{ + RenderTarget::setColorAttachment(attachment); + + if (!_defaultRenderTarget && bitmask::any(_flags, TargetBufferFlags::COLOR_ALL)) { + GLenum bufs[MAX_COLOR_ATTCHMENT] = { GL_NONE }; + for (size_t i = 0; i < MAX_COLOR_ATTCHMENT; ++i) { + if (bitmask::any(_flags, getMRTColorFlag(i))) { + auto textureInfo = attachment[i]; + auto textureHandler = textureInfo.texture != nullptr ? textureInfo.texture->getHandler() : 0; + glFramebufferTexture2D(GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0 + i, + GL_TEXTURE_2D, + textureHandler, + textureInfo.level); + bufs[i] = GL_COLOR_ATTACHMENT0 + i; + } + } +#if CC_TARGET_PLATFORM == CC_PLATFORM_WIN32 || CC_TARGET_PLATFORM == CC_PLATFORM_LINUX + glDrawBuffers(MAX_COLOR_ATTCHMENT, bufs); +#endif + CHECK_GL_ERROR_DEBUG(); + } +} + +void RenderTargetGL::setDepthAttachment(TextureBackend* attachment, int level) +{ + RenderTarget::setDepthAttachment(attachment, level); + + if (!_defaultRenderTarget) { + glFramebufferTexture2D(GL_FRAMEBUFFER, + GL_DEPTH_ATTACHMENT, + GL_TEXTURE_2D, + attachment != nullptr ? attachment->getHandler() : 0, + level); + + CHECK_GL_ERROR_DEBUG(); + } +} + +void RenderTargetGL::setStencilAttachment(TextureBackend* attachment, int level) +{ + RenderTarget::setStencilAttachment(attachment, level); + + if (!_defaultRenderTarget) { + glFramebufferTexture2D(GL_FRAMEBUFFER, + GL_STENCIL_ATTACHMENT, + GL_TEXTURE_2D, + attachment != nullptr ? attachment->getHandler() : 0, + level); + + CHECK_GL_ERROR_DEBUG(); + } +} + +CC_BACKEND_END diff --git a/cocos/renderer/backend/opengl/RenderTargetGL.h b/cocos/renderer/backend/opengl/RenderTargetGL.h new file mode 100644 index 0000000000..211ff5b34c --- /dev/null +++ b/cocos/renderer/backend/opengl/RenderTargetGL.h @@ -0,0 +1,26 @@ +#pragma once +#include "../RenderTarget.h" +#include "platform/CCGL.h" + +CC_BACKEND_BEGIN + +class RenderTargetGL : public RenderTarget +{ +public: + /* + * generateFBO, false, use for screen framebuffer + */ + RenderTargetGL(bool defaultRenderTarget); + ~RenderTargetGL(); + + void bindFrameBuffer() const override; + void unbindFrameBuffer() const override; + + void setColorAttachment(ColorAttachment attachment) override; + void setDepthAttachment(TextureBackend* attachment, int level = 0) override; + void setStencilAttachment(TextureBackend* attachment, int level = 0) override; +public: + GLuint _FBO = 0; +}; + +CC_BACKEND_END diff --git a/cocos/renderer/backend/opengl/TextureGL.cpp b/cocos/renderer/backend/opengl/TextureGL.cpp index b456384a84..6b640acfb2 100644 --- a/cocos/renderer/backend/opengl/TextureGL.cpp +++ b/cocos/renderer/backend/opengl/TextureGL.cpp @@ -151,10 +151,10 @@ Texture2DGL::Texture2DGL(const TextureDescriptor& descriptor) void Texture2DGL::initWithZeros() { - // Ensure the final data size at least 1 byte + // Ensure the final data size at least 4 byte _width = (std::max)(_width, (uint32_t)1); _height = (std::max)(_height, (uint32_t)1); - _bitsPerElement = (std::max)(_bitsPerElement, (uint8_t)8); + _bitsPerElement = (std::max)(_bitsPerElement, (uint8_t)(8 * 4)); auto size = _width * _height * _bitsPerElement / 8; uint8_t* data = (uint8_t*)malloc(size); diff --git a/cocos/renderer/backend/opengl/UtilsGL.cpp b/cocos/renderer/backend/opengl/UtilsGL.cpp index 1b298a37e0..86ea60c132 100644 --- a/cocos/renderer/backend/opengl/UtilsGL.cpp +++ b/cocos/renderer/backend/opengl/UtilsGL.cpp @@ -385,15 +385,9 @@ void UtilsGL::toGLTypes(PixelFormat textureFormat, GLint &internalFormat, GLuint // internalFormat = GL_DEPTH_COMPONENT; // type = GL_UNSIGNED_INT; case PixelFormat::D24S8: -#ifdef CC_USE_GLES format = GL_DEPTH_STENCIL_OES; internalFormat = GL_DEPTH_STENCIL_OES; type = GL_UNSIGNED_INT_24_8_OES; -#else - format = GL_DEPTH_STENCIL; - internalFormat = GL_DEPTH24_STENCIL8; - type = GL_UNSIGNED_INT_24_8; -#endif break; default: break; @@ -592,79 +586,4 @@ GLenum UtilsGL::toGLCullMode(CullMode mode) return GL_FRONT; } -void UtilsGL::readPixels(TextureBackend* texture, GLint x, GLint y, std::size_t width, std::size_t height, PixelBufferDescriptor& pbd) -{ - GLint defaultFBO = 0; - GLuint frameBuffer = 0; - - std::size_t bytesPerRow = 0; - if (UTILS_LIKELY(!texture)) // read pixels from screen - bytesPerRow = width * 4; - else { // read pixels from GPU texture - glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFBO); - - glGenFramebuffers(1, &frameBuffer); - glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer); - - /** Notes from cocos2d-x v3 - // TODO: move this to configuration, so we don't check it every time - // Certain Qualcomm Adreno GPU's will retain data in memory after a frame buffer switch which corrupts the render to the texture. The solution is to clear the frame buffer before rendering to the texture. However, calling glClear has the unintended result of clearing the current texture. Create a temporary texture to overcome this. At the end of RenderTexture::begin(), switch the attached texture to the second one, call glClear, and then switch back to the original texture. This solution is unnecessary for other devices as they don't have the same issue with switching frame buffers. - - if (Configuration::getInstance()->checkForGLExtension("GL_QCOM")) - { - // -- bind a temporary texture so we can clear the render buffer without losing our texture - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _textureCopy->getName(), 0); - CHECK_GL_ERROR_DEBUG(); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _texture->getName(), 0); - } - */ - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - texture->getTextureType() == TextureType::TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP, - static_cast(texture->getHandler()), - 0); - - bytesPerRow = width * texture->_bitsPerElement / 8; - } - - glPixelStorei(GL_PACK_ALIGNMENT, 1); - - auto bufferSize = bytesPerRow * height; -#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32 && defined(GL_ES_VERSION_3_0)) || \ - (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID && defined(GL_PIXEL_PACK_BUFFER)) - GLuint pbo; - glGenBuffers(1, &pbo); - glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo); - glBufferData(GL_PIXEL_PACK_BUFFER, bufferSize, nullptr, GL_STATIC_DRAW); - glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); - auto buffer = (uint8_t*)glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, bufferSize, GL_MAP_READ_BIT); -#else - std::unique_ptr bufferStorage(new uint8_t[bufferSize]); - auto buffer = bufferStorage.get(); - glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer); -#endif - uint8_t* wptr = pbd._data.resize(bufferSize); - if (buffer && wptr) { - auto rptr = buffer + (height - 1) * bytesPerRow; - for (int row = 0; row < height; ++row) { - memcpy(wptr, rptr, bytesPerRow); - wptr += bytesPerRow; - rptr -= bytesPerRow; - } - pbd._width = width; - pbd._height = height; - } -#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32 && defined(GL_ES_VERSION_3_0)) || \ - (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID && defined(GL_PIXEL_PACK_BUFFER)) - glUnmapBuffer(GL_PIXEL_PACK_BUFFER); - glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); - glDeleteBuffers(1, &pbo); -#endif - - if (UTILS_UNLIKELY(frameBuffer)) { - glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO); - glDeleteFramebuffers(1, &frameBuffer); - } -} - CC_BACKEND_END diff --git a/cocos/renderer/backend/opengl/UtilsGL.h b/cocos/renderer/backend/opengl/UtilsGL.h index bfc1226b66..836968fee8 100644 --- a/cocos/renderer/backend/opengl/UtilsGL.h +++ b/cocos/renderer/backend/opengl/UtilsGL.h @@ -34,9 +34,6 @@ CC_BACKEND_BEGIN * @addtogroup _opengl * @{ */ - -class TextureBackend; - /** * Convert backend enum class to corresponding opengl defined value. */ @@ -154,16 +151,6 @@ struct UtilsGL * @return Cull mode. */ static GLenum toGLCullMode(CullMode mode); - - /** - * Read a block of pixels from the given texture - * @param texture Specifies the texture to get the image, nullptr: read pixels from screen framebuffer - * @param origX,origY Specify the window coordinates of the first pixel that is read from the given texture. This location is the lower left corner of a rectangular block of pixels. - * @param rectWidth,rectHeight Specify the dimensions of the pixel rectangle. rectWidth and rectHeight of one correspond to a single pixel. - * @param pbd, the output pixel buffer for fill texels data - * @remark: !!!this function only can call after endFrame, then it's could be works well. - */ - static void readPixels(TextureBackend* texture, GLint x, GLint y, std::size_t width, std::size_t height, PixelBufferDescriptor& pbd); }; //end of _opengl group /// @} diff --git a/cocos/scripting/lua-bindings/auto/lua_cocos2dx_auto.cpp b/cocos/scripting/lua-bindings/auto/lua_cocos2dx_auto.cpp index cd8339fd6e..14caeb81c4 100644 --- a/cocos/scripting/lua-bindings/auto/lua_cocos2dx_auto.cpp +++ b/cocos/scripting/lua-bindings/auto/lua_cocos2dx_auto.cpp @@ -91251,9 +91251,9 @@ int lua_cocos2dx_Renderer_getStencilAttachment(lua_State* tolua_S) tolua_error(tolua_S,"invalid arguments in function 'lua_cocos2dx_Renderer_getStencilAttachment'", nullptr); return 0; } - cocos2d::Texture2D* ret = cobj->getStencilAttachment(); - object_to_luaval(tolua_S, "cc.Texture2D",(cocos2d::Texture2D*)ret); - return 1; + // cocos2d::Texture2D* ret = cobj->getStencilAttachment(); + // object_to_luaval(tolua_S, "cc.Texture2D",(cocos2d::Texture2D*)ret); + return 0; } luaL_error(tolua_S, "%s has wrong number of arguments: %d, was expecting %d \n", "cc.Renderer:getStencilAttachment",argc, 0); return 0; @@ -91698,9 +91698,9 @@ int lua_cocos2dx_Renderer_getColorAttachment(lua_State* tolua_S) tolua_error(tolua_S,"invalid arguments in function 'lua_cocos2dx_Renderer_getColorAttachment'", nullptr); return 0; } - cocos2d::Texture2D* ret = cobj->getColorAttachment(); - object_to_luaval(tolua_S, "cc.Texture2D",(cocos2d::Texture2D*)ret); - return 1; + // cocos2d::Texture2D* ret = cobj->getColorAttachment(); + // object_to_luaval(tolua_S, "cc.Texture2D",(cocos2d::Texture2D*)ret); + return 0; } luaL_error(tolua_S, "%s has wrong number of arguments: %d, was expecting %d \n", "cc.Renderer:getColorAttachment",argc, 0); return 0; @@ -93060,7 +93060,8 @@ int lua_cocos2dx_Renderer_setRenderTarget(lua_State* tolua_S) tolua_error(tolua_S,"invalid arguments in function 'lua_cocos2dx_Renderer_setRenderTarget'", nullptr); return 0; } - cobj->setRenderTarget(arg0, arg1, arg2, arg3); + // TODO: + // cobj->setRenderTarget(arg0, arg1, arg2, arg3); lua_settop(tolua_S, 1); return 1; } @@ -93107,9 +93108,9 @@ int lua_cocos2dx_Renderer_getDepthAttachment(lua_State* tolua_S) tolua_error(tolua_S,"invalid arguments in function 'lua_cocos2dx_Renderer_getDepthAttachment'", nullptr); return 0; } - cocos2d::Texture2D* ret = cobj->getDepthAttachment(); - object_to_luaval(tolua_S, "cc.Texture2D",(cocos2d::Texture2D*)ret); - return 1; + // cocos2d::Texture2D* ret = cobj->getDepthAttachment(); + // object_to_luaval(tolua_S, "cc.Texture2D",(cocos2d::Texture2D*)ret); + return 0; } luaL_error(tolua_S, "%s has wrong number of arguments: %d, was expecting %d \n", "cc.Renderer:getDepthAttachment",argc, 0); return 0; diff --git a/cocos/ui/UITextFieldEx.h b/cocos/ui/UITextFieldEx.h index ba20bb9f6b..8fa8acfb01 100644 --- a/cocos/ui/UITextFieldEx.h +++ b/cocos/ui/UITextFieldEx.h @@ -116,12 +116,12 @@ namespace ui { /** @brief Open keyboard and receive input text. */ - virtual bool attachWithIME(); + virtual bool attachWithIME() override; /** @brief End text input and close keyboard. */ - virtual bool detachWithIME(); + virtual bool detachWithIME() override; void keyboardDidShow(IMEKeyboardNotificationInfo& /*info*/) override; void keyboardDidHide(IMEKeyboardNotificationInfo& /*info*/) override; diff --git a/extensions/ImGuiEXT/CCImGuiEXT.cpp b/extensions/ImGuiEXT/CCImGuiEXT.cpp index 5982bf2d30..3a51e8db30 100644 --- a/extensions/ImGuiEXT/CCImGuiEXT.cpp +++ b/extensions/ImGuiEXT/CCImGuiEXT.cpp @@ -195,6 +195,7 @@ void ImGuiEXT::loadCustomFonts(void* ud) case CHS_GLYPH_RANGE::FULL: imChars = imFonts->GetGlyphRangesChineseFull(); break; + default:; } imFonts->AddFontFromFileTTF(fontInfo.first.c_str(), fontInfo.second.fontSize * contentZoomFactor, nullptr, imChars); diff --git a/extensions/cocostudio/CCDataReaderHelper.cpp b/extensions/cocostudio/CCDataReaderHelper.cpp index f19015ab2d..0cad06458d 100644 --- a/extensions/cocostudio/CCDataReaderHelper.cpp +++ b/extensions/cocostudio/CCDataReaderHelper.cpp @@ -366,10 +366,6 @@ void DataReaderHelper::addDataFromFileAsync(const std::string& imagePath, const { basefilePath = basefilePath.substr(0, pos + 1); } - else - { - basefilePath; - } // lazy init diff --git a/templates/cocos2dx_files.json b/templates/cocos2dx_files.json index 89ed04734b..df9defae7a 100644 --- a/templates/cocos2dx_files.json +++ b/templates/cocos2dx_files.json @@ -1037,8 +1037,8 @@ "cocos/renderer/backend/ProgramCache.h", "cocos/renderer/backend/ProgramState.cpp", "cocos/renderer/backend/ProgramState.h", - "cocos/renderer/backend/RenderPassDescriptor.cpp", - "cocos/renderer/backend/RenderPassDescriptor.h", + "cocos/renderer/backend/RenderPassParams.cpp", + "cocos/renderer/backend/RenderPassParams.h", "cocos/renderer/backend/RenderPipeline.h", "cocos/renderer/backend/RenderPipelineDescriptor.h", "cocos/renderer/backend/ShaderCache.cpp", diff --git a/tools/travis-scripts/run-script.sh b/tools/travis-scripts/run-script.sh index eaebef33b6..043256ba73 100755 --- a/tools/travis-scripts/run-script.sh +++ b/tools/travis-scripts/run-script.sh @@ -50,7 +50,7 @@ function build_mac_cmake() cd $COCOS2DX_ROOT mkdir -p build cmake -S . -B build -GXcode -DBUILD_EXTENSION_IMGUI=ON - cmake --build build --config Release -- -quiet + cmake --build build --config Release --target cpp-tests -- -quiet #xcodebuild -project Cocos2d-x.xcodeproj -alltargets -jobs $NUM_OF_CORES build | xcpretty ##the following commands must not be removed #xcodebuild -project Cocos2d-x.xcodeproj -alltargets -jobs $NUM_OF_CORES build