#if defined(OS_MAC_OS_X) || defined(OS_IOS) #include #else #include #endif #include #include "Combiner.h" #include "FrameBuffer.h" #include "DepthBuffer.h" #include "VI.h" #include "Config.h" #include "DebugDump.h" #include #include #include "DisplayWindow.h" using namespace graphics; DepthBuffer::DepthBuffer() { m_copyFBO = gfxContext.createFramebuffer(); } DepthBuffer::~DepthBuffer() { gfxContext.deleteFramebuffer(m_depthRenderbuffer); gfxContext.deleteFramebuffer(m_copyFBO); gfxContext.deleteFramebuffer(m_ZTextureClearFBO); gfxContext.deleteFramebuffer(m_DeltaZTextureClearFBO); textureCache().removeFrameBufferTexture(m_pDepthImageZTexture); textureCache().removeFrameBufferTexture(m_pDepthImageDeltaZTexture); textureCache().removeFrameBufferTexture(m_pDepthBufferTexture); textureCache().removeFrameBufferTexture(m_pResolveDepthBufferTexture); textureCache().removeFrameBufferTexture(m_pDepthBufferCopyTexture); } void DepthBuffer::_initDepthImageTexture(FrameBuffer * _pBuffer, CachedTexture& _cachedTexture, graphics::ObjectHandle & _clearFBO) { const FramebufferTextureFormats & fbTexFormat = gfxContext.getFramebufferTextureFormats(); _cachedTexture.width = _pBuffer->m_pTexture->width; _cachedTexture.height = _pBuffer->m_pTexture->height; _cachedTexture.format = 0; _cachedTexture.size = 2; _cachedTexture.clampS = 1; _cachedTexture.clampT = 1; _cachedTexture.address = _pBuffer->m_startAddress; _cachedTexture.clampWidth = static_cast(_pBuffer->m_width); _cachedTexture.clampHeight = static_cast(_pBuffer->m_height); _cachedTexture.frameBufferTexture = CachedTexture::fbOneSample; _cachedTexture.maskS = 0; _cachedTexture.maskT = 0; _cachedTexture.mirrorS = 0; _cachedTexture.mirrorT = 0; _cachedTexture.textureBytes = _cachedTexture.width * _cachedTexture.height * fbTexFormat.depthImageFormatBytes; { Context::InitTextureParams params; params.handle = _cachedTexture.name; params.width = _cachedTexture.width; params.height = _cachedTexture.height; params.internalFormat = fbTexFormat.depthImageInternalFormat; params.format = fbTexFormat.depthImageFormat; params.dataType = fbTexFormat.depthImageType; gfxContext.init2DTexture(params); } { Context::TexParameters params; params.handle = _cachedTexture.name; params.target = textureTarget::TEXTURE_2D; params.textureUnitIndex = textureIndices::Tex[0]; params.minFilter = textureParameters::FILTER_NEAREST; params.magFilter = textureParameters::FILTER_NEAREST; gfxContext.setTextureParameters(params); } { Context::FrameBufferRenderTarget targetParams; targetParams.bufferHandle = _clearFBO; targetParams.bufferTarget = bufferTarget::DRAW_FRAMEBUFFER; targetParams.attachment = bufferAttachment::COLOR_ATTACHMENT0; targetParams.textureHandle = _cachedTexture.name; targetParams.textureTarget = textureTarget::TEXTURE_2D; gfxContext.addFrameBufferRenderTarget(targetParams); } } void DepthBuffer::initDepthImageTexture(FrameBuffer * _pBuffer) { if (config.frameBufferEmulation.N64DepthCompare == Config::dcDisable || m_pDepthImageZTexture != nullptr) return; m_pDepthImageZTexture = textureCache().addFrameBufferTexture(textureTarget::TEXTURE_2D); m_ZTextureClearFBO = gfxContext.createFramebuffer(); m_pDepthImageDeltaZTexture = textureCache().addFrameBufferTexture(textureTarget::TEXTURE_2D); m_DeltaZTextureClearFBO = gfxContext.createFramebuffer(); _initDepthImageTexture(_pBuffer, *m_pDepthImageZTexture, m_ZTextureClearFBO); _initDepthImageTexture(_pBuffer, *m_pDepthImageDeltaZTexture, m_DeltaZTextureClearFBO); depthBufferList().clearBuffer(); } void DepthBuffer::_initDepthBufferTexture(const FrameBuffer * _pBuffer, CachedTexture * _pTexture, bool _multisample) { const FramebufferTextureFormats & fbTexFormat = gfxContext.getFramebufferTextureFormats(); if (_pBuffer != nullptr) { _pTexture->width = _pBuffer->m_pTexture->width; _pTexture->height = _pBuffer->m_pTexture->height; _pTexture->address = _pBuffer->m_startAddress; _pTexture->clampWidth = static_cast(_pBuffer->m_width); _pTexture->clampHeight = VI_GetMaxBufferHeight(static_cast(_pBuffer->m_width)); _pTexture->hdRatioS = _pBuffer->m_scale; _pTexture->hdRatioT = _pBuffer->m_scale; } else { const u16 maxHeight = VI_GetMaxBufferHeight(static_cast(VI.width)); if (config.frameBufferEmulation.nativeResFactor == 0) { _pTexture->width = static_cast(dwnd().getWidth()); _pTexture->height = static_cast(static_cast(static_cast(maxHeight) * dwnd().getScaleX())); } else { _pTexture->width = static_cast(VI.width * config.frameBufferEmulation.nativeResFactor); _pTexture->height = static_cast(maxHeight * config.frameBufferEmulation.nativeResFactor); } _pTexture->address = gDP.depthImageAddress; _pTexture->clampWidth = static_cast(VI.width); _pTexture->clampHeight = maxHeight; } _pTexture->format = 0; _pTexture->size = 2; _pTexture->clampS = 1; _pTexture->clampT = 1; _pTexture->frameBufferTexture = CachedTexture::fbOneSample; _pTexture->maskS = 0; _pTexture->maskT = 0; _pTexture->mirrorS = 0; _pTexture->mirrorT = 0; _pTexture->textureBytes = _pTexture->width * _pTexture->height * fbTexFormat.depthFormatBytes; Context::InitTextureParams initParams; initParams.handle = _pTexture->name; initParams.msaaLevel = _multisample ? config.video.multisampling : 0U; initParams.width = _pTexture->width; initParams.height = _pTexture->height; initParams.internalFormat = fbTexFormat.depthInternalFormat; initParams.format = fbTexFormat.depthFormat; initParams.dataType = fbTexFormat.depthType; gfxContext.init2DTexture(initParams); if (!_multisample) { _pTexture->frameBufferTexture = CachedTexture::fbOneSample; Context::TexParameters texParams; texParams.handle = _pTexture->name; texParams.target = textureTarget::TEXTURE_2D; texParams.textureUnitIndex = textureIndices::Tex[0]; texParams.minFilter = textureParameters::FILTER_NEAREST; texParams.magFilter = textureParameters::FILTER_NEAREST; gfxContext.setTextureParameters(texParams); } else { _pTexture->frameBufferTexture = CachedTexture::fbMultiSample; } } void DepthBuffer::_initDepthBufferRenderbuffer(FrameBuffer * _pBuffer) { if (m_depthRenderbuffer.isNotNull()) return; u32 height; if (_pBuffer != nullptr) { m_depthRenderbufferWidth = _pBuffer->m_pTexture->width; height = _pBuffer->m_pTexture->height; } else { if (config.frameBufferEmulation.nativeResFactor == 0) { m_depthRenderbufferWidth = dwnd().getWidth(); height = static_cast(static_cast(VI_GetMaxBufferHeight(static_cast(VI.width))) * dwnd().getScaleX()); } else { m_depthRenderbufferWidth = VI.width * config.frameBufferEmulation.nativeResFactor; height = VI_GetMaxBufferHeight(static_cast(VI.width)) * config.frameBufferEmulation.nativeResFactor; } } m_depthRenderbuffer = gfxContext.createRenderbuffer(); Context::InitRenderbufferParams params; params.handle = m_depthRenderbuffer; params.target = textureTarget::RENDERBUFFER; params.format = gfxContext.getFramebufferTextureFormats().depthInternalFormat; params.width = m_depthRenderbufferWidth; params.height = height; gfxContext.initRenderbuffer(params); } void DepthBuffer::setDepthAttachment(ObjectHandle _fbo, BufferTargetParam _target) { Context::FrameBufferRenderTarget params; params.attachment = bufferAttachment::DEPTH_ATTACHMENT; params.bufferHandle = _fbo; params.bufferTarget = _target; if (Context::DepthFramebufferTextures) { params.textureHandle = m_pDepthBufferTexture->name; params.textureTarget = config.video.multisampling != 0 ? textureTarget::TEXTURE_2D_MULTISAMPLE : textureTarget::TEXTURE_2D; } else { params.textureHandle = m_depthRenderbuffer; params.textureTarget = textureTarget::RENDERBUFFER; } gfxContext.addFrameBufferRenderTarget(params); m_copied = false; m_resolved = false; } void DepthBuffer::initDepthBufferTexture(FrameBuffer * _pBuffer) { if (Context::DepthFramebufferTextures) { if (m_pDepthBufferTexture == nullptr) { m_pDepthBufferTexture = textureCache().addFrameBufferTexture(config.video.multisampling != 0 ? textureTarget::TEXTURE_2D_MULTISAMPLE : textureTarget::TEXTURE_2D); _initDepthBufferTexture(_pBuffer, m_pDepthBufferTexture, config.video.multisampling != 0); } } else { _initDepthBufferRenderbuffer(_pBuffer); } if (config.video.multisampling != 0 && m_pResolveDepthBufferTexture == nullptr) { m_pResolveDepthBufferTexture = textureCache().addFrameBufferTexture(textureTarget::TEXTURE_2D); _initDepthBufferTexture(_pBuffer, m_pResolveDepthBufferTexture, false); } } CachedTexture * DepthBuffer::resolveDepthBufferTexture(FrameBuffer * _pBuffer) { if (config.video.multisampling == 0) return m_pDepthBufferTexture; if (m_resolved) return m_pResolveDepthBufferTexture; Context::FrameBufferRenderTarget targetParams; targetParams.attachment = bufferAttachment::DEPTH_ATTACHMENT; targetParams.bufferHandle = _pBuffer->m_resolveFBO; targetParams.bufferTarget = bufferTarget::DRAW_FRAMEBUFFER; targetParams.textureHandle = m_pResolveDepthBufferTexture->name; targetParams.textureTarget = textureTarget::TEXTURE_2D; gfxContext.addFrameBufferRenderTarget(targetParams); Context::BlitFramebuffersParams blitParams; blitParams.readBuffer = _pBuffer->m_FBO; blitParams.drawBuffer = _pBuffer->m_resolveFBO; blitParams.srcX0 = 0; blitParams.srcY0 = 0; blitParams.srcX1 = m_pDepthBufferTexture->width; blitParams.srcY1 = m_pDepthBufferTexture->height; blitParams.dstX0 = 0; blitParams.dstY0 = 0; blitParams.dstX1 = m_pResolveDepthBufferTexture->width; blitParams.dstY1 = m_pResolveDepthBufferTexture->height; blitParams.mask = blitMask::DEPTH_BUFFER; blitParams.filter = textureParameters::FILTER_NEAREST; gfxContext.blitFramebuffers(blitParams); gfxContext.bindFramebuffer(bufferTarget::READ_FRAMEBUFFER, ObjectHandle::defaultFramebuffer); gfxContext.bindFramebuffer(bufferTarget::DRAW_FRAMEBUFFER, _pBuffer->m_FBO); m_resolved = true; return m_pResolveDepthBufferTexture; } void DepthBuffer::copyDepthBufferTexture(FrameBuffer * _pBuffer, CachedTexture *& _pTexture, graphics::ObjectHandle _copyFBO) { if (_pTexture == nullptr) { _pTexture = textureCache().addFrameBufferTexture(textureTarget::TEXTURE_2D); _initDepthBufferTexture(_pBuffer, _pTexture, false); } Context::FrameBufferRenderTarget targetParams; targetParams.bufferHandle = _copyFBO; targetParams.bufferTarget = bufferTarget::DRAW_FRAMEBUFFER; targetParams.attachment = bufferAttachment::COLOR_ATTACHMENT0; targetParams.textureHandle = _pBuffer->m_pTexture->frameBufferTexture == CachedTexture::fbMultiSample ? _pBuffer->m_pResolveTexture->name : _pBuffer->m_pTexture->name; targetParams.textureTarget = textureTarget::TEXTURE_2D; gfxContext.addFrameBufferRenderTarget(targetParams); targetParams.attachment = bufferAttachment::DEPTH_ATTACHMENT; targetParams.textureHandle = _pTexture->name; gfxContext.addFrameBufferRenderTarget(targetParams); Context::BlitFramebuffersParams blitParams; blitParams.readBuffer = _pBuffer->m_FBO; blitParams.drawBuffer = _copyFBO; blitParams.srcX0 = blitParams.dstX0 = 0; blitParams.srcY0 = blitParams.dstY0 = 0; blitParams.srcX1 = blitParams.dstX1 = _pTexture->width; blitParams.srcY1 = blitParams.dstY1 = _pTexture->height; blitParams.mask = blitMask::DEPTH_BUFFER; blitParams.filter = textureParameters::FILTER_NEAREST; gfxContext.blitFramebuffers(blitParams); gfxContext.bindFramebuffer(bufferTarget::READ_FRAMEBUFFER, ObjectHandle::defaultFramebuffer); gfxContext.bindFramebuffer(bufferTarget::DRAW_FRAMEBUFFER, _pBuffer->m_FBO); } CachedTexture * DepthBuffer::copyDepthBufferTexture(FrameBuffer * _pBuffer) { if (m_copied) return m_pDepthBufferCopyTexture; DepthBuffer::copyDepthBufferTexture(_pBuffer, m_pDepthBufferCopyTexture, m_copyFBO); m_copied = true; return m_pDepthBufferCopyTexture; } void DepthBuffer::activateDepthBufferTexture(FrameBuffer * _pBuffer) { textureCache().activateTexture(0, resolveDepthBufferTexture(_pBuffer)); gfxContext.textureBarrier(); } void DepthBuffer::bindDepthImageTexture(ObjectHandle _fbo) { if (Context::FramebufferFetchDepth) { Context::FrameBufferRenderTarget targetParams; targetParams.bufferHandle = _fbo; targetParams.bufferTarget = bufferTarget::DRAW_FRAMEBUFFER; targetParams.attachment = bufferAttachment::COLOR_ATTACHMENT1; targetParams.textureHandle = m_pDepthImageZTexture->name; targetParams.textureTarget = textureTarget::TEXTURE_2D; gfxContext.addFrameBufferRenderTarget(targetParams); targetParams.attachment = bufferAttachment::COLOR_ATTACHMENT2; targetParams.textureHandle = m_pDepthImageDeltaZTexture->name; gfxContext.addFrameBufferRenderTarget(targetParams); gfxContext.setDrawBuffers(3); } else if (Context::ImageTextures) { Context::BindImageTextureParameters bindParams; bindParams.imageUnit = textureImageUnits::DepthZ; bindParams.texture = m_pDepthImageZTexture->name; bindParams.accessMode = textureImageAccessMode::READ_WRITE; bindParams.textureFormat = gfxContext.getFramebufferTextureFormats().depthImageInternalFormat; gfxContext.bindImageTexture(bindParams); bindParams.imageUnit = textureImageUnits::DepthDeltaZ; bindParams.texture = m_pDepthImageDeltaZTexture->name; gfxContext.bindImageTexture(bindParams); } } DepthBufferList::DepthBufferList() : m_pCurrent(nullptr), m_pzLUT(nullptr) { m_pzLUT = new u16[0x40000]; for (u32 i = 0; i<0x40000; i++) { u32 exponent = 0; u32 testbit = 1 << 17; while ((i & testbit) && (exponent < 7)) { exponent++; testbit = 1 << (17 - exponent); } const u32 mantissa = (i >> (6 - (6 < exponent ? 6 : exponent))) & 0x7ff; m_pzLUT[i] = static_cast(((exponent << 11) | mantissa) << 2); } } DepthBufferList::~DepthBufferList() { delete[] m_pzLUT; m_pzLUT = nullptr; m_list.clear(); } DepthBufferList & DepthBufferList::get() { static DepthBufferList depthBufferList; return depthBufferList; } void DepthBufferList::init() { m_pCurrent = nullptr; } void DepthBufferList::destroy() { m_pCurrent = nullptr; m_list.clear(); } void DepthBufferList::setCleared(bool _cleared) { for (DepthBuffers::iterator iter = m_list.begin(); iter != m_list.end(); ++iter) iter->m_cleared = _cleared; } DepthBuffer * DepthBufferList::findBuffer(u32 _address) { for (DepthBuffers::iterator iter = m_list.begin(); iter != m_list.end(); ++iter) if (iter->m_address == _address) return &(*iter); return nullptr; } void DepthBufferList::removeBuffer(u32 _address ) { for (DepthBuffers::iterator iter = m_list.begin(); iter != m_list.end(); ++iter) if (iter->m_address == _address) { frameBufferList().clearDepthBuffer(&(*iter)); m_list.erase(iter); return; } } void DepthBufferList::_createScreenSizeBuffer(u32 _address) { FrameBuffer * pFrameBuffer = frameBufferList().findBuffer(VI.width*2); if (pFrameBuffer == nullptr) return; m_list.emplace_front(); DepthBuffer & buffer = m_list.front(); buffer.m_address = _address; buffer.m_width = pFrameBuffer->m_width; buffer.initDepthBufferTexture(pFrameBuffer); m_pCurrent = &buffer; frameBufferList().attachDepthBuffer(); m_pCurrent = nullptr; } void DepthBufferList::saveBuffer(u32 _address) { if (config.frameBufferEmulation.enable == 0) { if (m_list.empty()) _createScreenSizeBuffer(_address); return; } FrameBuffer * pFrameBuffer = frameBufferList().findBuffer(_address); if (pFrameBuffer != nullptr) pFrameBuffer->m_isDepthBuffer = true; DepthBuffer * pDepthBuffer = nullptr; if (pFrameBuffer != nullptr && pFrameBuffer->m_startAddress != _address) pDepthBuffer = findBuffer(pFrameBuffer->m_startAddress); else pDepthBuffer = findBuffer(_address); if (pDepthBuffer != nullptr && pFrameBuffer != nullptr && pDepthBuffer->m_width != pFrameBuffer->m_width) { removeBuffer(_address); pDepthBuffer = nullptr; } if (pDepthBuffer == nullptr) { m_list.emplace_front(); DepthBuffer & buffer = m_list.front(); buffer.m_address = _address; buffer.m_width = pFrameBuffer != nullptr ? pFrameBuffer->m_width : VI.width; buffer.initDepthBufferTexture(pFrameBuffer); pDepthBuffer = &buffer; } DepthBuffer * pCurrent = m_pCurrent; m_pCurrent = pDepthBuffer; frameBufferList().attachDepthBuffer(); if (pFrameBuffer == nullptr && (config.generalEmulation.hacks & hack_clearAloneDepthBuffer) != 0) clearBuffer(); if (pDepthBuffer->m_address != gDP.depthImageAddress) m_pCurrent = pCurrent; } void DepthBufferList::clearBuffer() { if (m_pCurrent != nullptr) m_pCurrent->m_cleared = true; if (config.frameBufferEmulation.enable == 0 || config.frameBufferEmulation.N64DepthCompare == Config::dcDisable) { gfxContext.clearDepthBuffer(); return; } // Clear depth image texture FrameBuffer * pColorBuffer = frameBufferList().getCurrent(); if (pColorBuffer == nullptr || pColorBuffer->m_pDepthBuffer == nullptr) return; DepthBuffer * pDepthBuffer = pColorBuffer->m_pDepthBuffer; //if (pColorBuffer->m_pTexture->realWidth == pDepthBuffer->m_pDepthImageZTexture->realWidth) { gfxContext.bindFramebuffer(bufferTarget::DRAW_FRAMEBUFFER, pDepthBuffer->m_ZTextureClearFBO); gfxContext.clearColorBuffer(1.0f, 0.0f, 0.0f, 0.0f); gfxContext.bindFramebuffer(bufferTarget::DRAW_FRAMEBUFFER, pDepthBuffer->m_DeltaZTextureClearFBO); gfxContext.clearColorBuffer(1.0f, 0.0f, 0.0f, 0.0f); } //else { // gDP.rectColor.g = gDP.rectColor.b = gDP.rectColor.a = 0.0f; // u32 cycleType = gDP.otherMode.cycleType; // u32 fillcolor = gDP.fillColor.color; // gDP.otherMode.cycleType = G_CYC_FILL; // gDP.fillColor.color = 0; // const int lrx = pColorBuffer->m_width; // const int lry = VI_GetMaxBufferHeight(pColorBuffer->m_width); // gDP.rectColor.r = 1.0f; // gfxContext.bindFramebuffer(bufferTarget::DRAW_FRAMEBUFFER, pDepthBuffer->m_ZTextureClearFBO); // dwnd().getDrawer().drawRect(0, 0, lrx, lry); // gDP.rectColor.r = 0.0f; // gfxContext.bindFramebuffer(bufferTarget::DRAW_FRAMEBUFFER, pDepthBuffer->m_DeltaZTextureClearFBO); // dwnd().getDrawer().drawRect(0, 0, lrx, lry); // gDP.otherMode.cycleType = cycleType; // gDP.fillColor.color = fillcolor; //} frameBufferList().setCurrentDrawBuffer(); } void DepthBuffer_Init() { depthBufferList().init(); } void DepthBuffer_Destroy() { depthBufferList().destroy(); }