| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296 |
- // Copyright (C) 2009-2017, Panagiotis Christopoulos Charitos and contributors.
- // All rights reserved.
- // Code licensed under the BSD License.
- // http://www.anki3d.org/LICENSE
- #include <anki/gr/gl/FramebufferImpl.h>
- #include <anki/gr/Texture.h>
- #include <anki/gr/gl/TextureViewImpl.h>
- #include <anki/gr/gl/GlState.h>
- #include <anki/gr/GrManager.h>
- #include <anki/gr/gl/GrManagerImpl.h>
- #include <anki/gr/gl/RenderingThread.h>
- #include <anki/util/Logger.h>
- namespace anki
- {
- Error FramebufferImpl::init(const FramebufferInitInfo& init)
- {
- ANKI_ASSERT(!isCreated());
- m_in = init;
- if(init.refersToDefaultFramebuffer())
- {
- m_fbSize[0] = m_fbSize[1] = MAX_U16;
- m_bindDefault = true;
- return Error::NONE;
- }
- m_bindDefault = false;
- glGenFramebuffers(1, &m_glName);
- ANKI_ASSERT(m_glName != 0);
- const GLenum target = GL_FRAMEBUFFER;
- glBindFramebuffer(target, m_glName);
- // Attach color
- for(U i = 0; i < m_in.m_colorAttachmentCount; i++)
- {
- const FramebufferAttachmentInfo& att = m_in.m_colorAttachments[i];
- const TextureViewImpl& viewImpl = static_cast<const TextureViewImpl&>(*att.m_textureView);
- ANKI_ASSERT(viewImpl.m_tex->isSubresourceGoodForFramebufferAttachment(viewImpl.getSubresource()));
- const GLenum binding = GL_COLOR_ATTACHMENT0 + i;
- attachTextureInternal(binding, viewImpl, att);
- m_drawBuffers[i] = binding;
- if(att.m_loadOperation == AttachmentLoadOperation::DONT_CARE)
- {
- m_invalidateBuffers[m_invalidateBuffersCount++] = binding;
- }
- if(m_fbSize[0] == 0)
- {
- m_fbSize[0] = viewImpl.m_tex->getWidth() >> viewImpl.getBaseMipmap();
- m_fbSize[1] = viewImpl.m_tex->getHeight() >> viewImpl.getBaseMipmap();
- }
- else
- {
- ANKI_ASSERT(m_fbSize[0] == (viewImpl.m_tex->getWidth() >> viewImpl.getBaseMipmap()));
- ANKI_ASSERT(m_fbSize[1] == (viewImpl.m_tex->getHeight() >> viewImpl.getBaseMipmap()));
- }
- }
- // Attach depth/stencil
- if(m_in.m_depthStencilAttachment.m_textureView.isCreated())
- {
- const FramebufferAttachmentInfo& att = m_in.m_depthStencilAttachment;
- const TextureViewImpl& viewImpl = static_cast<const TextureViewImpl&>(*att.m_textureView);
- ANKI_ASSERT(viewImpl.m_tex->isSubresourceGoodForFramebufferAttachment(viewImpl.getSubresource()));
- GLenum binding;
- if(viewImpl.getDepthStencilAspect() == DepthStencilAspectBit::DEPTH)
- {
- binding = GL_DEPTH_ATTACHMENT;
- }
- else if(viewImpl.getDepthStencilAspect() == DepthStencilAspectBit::STENCIL)
- {
- binding = GL_STENCIL_ATTACHMENT;
- }
- else
- {
- ANKI_ASSERT(viewImpl.getDepthStencilAspect() == DepthStencilAspectBit::DEPTH_STENCIL);
- binding = GL_DEPTH_STENCIL_ATTACHMENT;
- }
- attachTextureInternal(binding, viewImpl, att);
- if(att.m_loadOperation == AttachmentLoadOperation::DONT_CARE)
- {
- m_invalidateBuffers[m_invalidateBuffersCount++] = binding;
- }
- if(m_fbSize[0] == 0)
- {
- m_fbSize[0] = viewImpl.m_tex->getWidth() >> viewImpl.getBaseMipmap();
- m_fbSize[1] = viewImpl.m_tex->getHeight() >> viewImpl.getBaseMipmap();
- }
- else
- {
- ANKI_ASSERT(m_fbSize[0] == (viewImpl.m_tex->getWidth() >> viewImpl.getBaseMipmap()));
- ANKI_ASSERT(m_fbSize[1] == (viewImpl.m_tex->getHeight() >> viewImpl.getBaseMipmap()));
- }
- // Misc
- m_clearDepth = !!(viewImpl.getDepthStencilAspect() & DepthStencilAspectBit::DEPTH)
- && att.m_loadOperation == AttachmentLoadOperation::CLEAR;
- m_clearStencil = !!(viewImpl.getDepthStencilAspect() & DepthStencilAspectBit::STENCIL)
- && att.m_stencilLoadOperation == AttachmentLoadOperation::CLEAR;
- }
- // Check completeness
- GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
- if(status != GL_FRAMEBUFFER_COMPLETE)
- {
- ANKI_GL_LOGE("FBO is incomplete. Status: 0x%x", status);
- return Error::FUNCTION_FAILED;
- }
- glBindFramebuffer(GL_FRAMEBUFFER, 0);
- return Error::NONE;
- }
- void FramebufferImpl::attachTextureInternal(
- GLenum attachment, const TextureViewImpl& view, const FramebufferAttachmentInfo& info)
- {
- const GLenum target = GL_FRAMEBUFFER;
- const TextureImpl& tex = static_cast<const TextureImpl&>(*view.m_tex);
- switch(tex.m_target)
- {
- case GL_TEXTURE_2D:
- #if ANKI_GL == ANKI_GL_DESKTOP
- case GL_TEXTURE_2D_MULTISAMPLE:
- #endif
- glFramebufferTexture2D(target, attachment, tex.m_target, tex.getGlName(), view.getBaseMipmap());
- break;
- case GL_TEXTURE_CUBE_MAP:
- glFramebufferTexture2D(target,
- attachment,
- GL_TEXTURE_CUBE_MAP_POSITIVE_X + view.getBaseFace(),
- tex.getGlName(),
- view.getBaseMipmap());
- break;
- case GL_TEXTURE_2D_ARRAY:
- glFramebufferTextureLayer(target, attachment, tex.getGlName(), view.getBaseMipmap(), view.getBaseLayer());
- break;
- case GL_TEXTURE_3D:
- ANKI_ASSERT(!"TODO");
- break;
- case GL_TEXTURE_CUBE_MAP_ARRAY:
- glFramebufferTextureLayer(
- target, attachment, tex.getGlName(), view.getBaseMipmap(), view.getBaseLayer() * 6 + view.getBaseFace());
- break;
- default:
- ANKI_ASSERT(0);
- break;
- }
- }
- void FramebufferImpl::bind(const GlState& state, U32 minx, U32 miny, U32 width, U32 height) const
- {
- ANKI_ASSERT(width > 0 && height > 0);
- if(m_in.getName() && static_cast<const GrManagerImpl&>(getManager()).debugMarkersEnabled())
- {
- glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, m_glName, 0, &m_in.getName()[0]);
- }
- // Clear in the render area
- const U maxx = min<U>(minx + width, m_fbSize[0]);
- const U maxy = min<U>(miny + height, m_fbSize[1]);
- ANKI_ASSERT(minx < m_fbSize[0] && miny < m_fbSize[1] && maxx <= m_fbSize[0] && maxy <= m_fbSize[1]);
- width = maxx - minx;
- height = maxy - miny;
- glScissor(minx, miny, width, height);
- if(m_bindDefault)
- {
- glBindFramebuffer(GL_FRAMEBUFFER, 0);
- const FramebufferAttachmentInfo& att = m_in.m_colorAttachments[0];
- if(att.m_loadOperation == AttachmentLoadOperation::CLEAR)
- {
- glClearBufferfv(GL_COLOR, 0, &att.m_clearValue.m_colorf[0]);
- }
- else
- {
- /* For some reason the driver reports error
- ANKI_ASSERT(
- att.m_loadOperation == AttachmentLoadOperation::DONT_CARE);
- GLenum buff = GL_COLOR_ATTACHMENT0;
- glInvalidateFramebuffer(GL_FRAMEBUFFER, 1, &buff);*/
- }
- }
- else
- {
- ANKI_ASSERT(m_glName != 0);
- glBindFramebuffer(GL_FRAMEBUFFER, m_glName);
- // Set the draw buffers
- if(m_in.m_colorAttachmentCount)
- {
- glDrawBuffers(m_in.m_colorAttachmentCount, &m_drawBuffers[0]);
- }
- // Invalidate
- if(m_invalidateBuffersCount)
- {
- glInvalidateSubFramebuffer(
- GL_FRAMEBUFFER, m_invalidateBuffersCount, &m_invalidateBuffers[0], minx, miny, width, height);
- }
- // Clear buffers
- for(U i = 0; i < m_in.m_colorAttachmentCount; i++)
- {
- const FramebufferAttachmentInfo& att = m_in.m_colorAttachments[i];
- if(att.m_loadOperation == AttachmentLoadOperation::CLEAR)
- {
- // Enable write mask in case a pipeline changed it (else no clear will happen) and then restore state
- Bool restore = false;
- if(state.m_colorWriteMasks[i][0] != true || state.m_colorWriteMasks[i][1] != true
- || state.m_colorWriteMasks[i][2] != true
- || state.m_colorWriteMasks[i][3] != true)
- {
- glColorMaski(i, true, true, true, true);
- restore = true;
- }
- glClearBufferfv(GL_COLOR, i, &att.m_clearValue.m_colorf[0]);
- if(restore)
- {
- glColorMaski(i,
- state.m_colorWriteMasks[i][0],
- state.m_colorWriteMasks[i][1],
- state.m_colorWriteMasks[i][2],
- state.m_colorWriteMasks[i][3]);
- }
- }
- }
- // Clear depth
- if(m_clearDepth)
- {
- // Enable write mask in case a pipeline changed it (else no clear will happen) and then restore state
- if(state.m_depthWriteMask == false)
- {
- glDepthMask(true);
- }
- glClearBufferfv(GL_DEPTH, 0, &m_in.m_depthStencilAttachment.m_clearValue.m_depthStencil.m_depth);
- if(state.m_depthWriteMask == false)
- {
- glDepthMask(false);
- }
- }
- // Clear stencil
- if(m_clearStencil)
- {
- // Enable write mask in case a pipeline changed it (else no clear will happen) and then restore state
- // From the spec: The clear operation always uses the front stencil write mask when clearing the stencil
- // buffer
- if(state.m_stencilWriteMask[0] != MAX_U32)
- {
- glStencilMaskSeparate(GL_FRONT, MAX_U32);
- }
- GLint clearVal = m_in.m_depthStencilAttachment.m_clearValue.m_depthStencil.m_stencil;
- glClearBufferiv(GL_STENCIL, 0, &clearVal);
- if(state.m_stencilWriteMask[0] != MAX_U32)
- {
- glStencilMaskSeparate(GL_FRONT, state.m_stencilWriteMask[0]);
- }
- }
- }
- glScissor(state.m_scissor[0], state.m_scissor[1], state.m_scissor[2], state.m_scissor[3]);
- }
- void FramebufferImpl::endRenderPass() const
- {
- if(m_in.getName() && static_cast<const GrManagerImpl&>(getManager()).debugMarkersEnabled())
- {
- glPopDebugGroup();
- }
- }
- } // end namespace anki
|