diff --git a/Runtime/Graphics/CCubeRenderer.cpp b/Runtime/Graphics/CCubeRenderer.cpp index 97aa7b9fe..bbe2363cc 100644 --- a/Runtime/Graphics/CCubeRenderer.cpp +++ b/Runtime/Graphics/CCubeRenderer.cpp @@ -640,9 +640,9 @@ void CCubeRenderer::SetPerspective(float fovy, float width, float height, float } std::pair CCubeRenderer::SetViewportOrtho(bool centered, float znear, float zfar) { - auto left = static_cast(centered ? CGraphics::GetViewportLeft() - CGraphics::GetViewportWidth() / 2 + auto left = static_cast(centered ? CGraphics::GetViewportLeft() - CGraphics::GetViewportHalfWidth() : CGraphics::GetViewportLeft()); - auto top = static_cast(centered ? CGraphics::GetViewportTop() - CGraphics::GetViewportHeight() / 2 + auto top = static_cast(centered ? CGraphics::GetViewportTop() - CGraphics::GetViewportHalfHeight() : CGraphics::GetViewportHeight()); auto right = static_cast(CGraphics::GetViewportLeft() + (centered ? CGraphics::GetViewportWidth() / 2 : CGraphics::GetViewportWidth())); diff --git a/Runtime/Graphics/CGraphics.hpp b/Runtime/Graphics/CGraphics.hpp index acdd3c6b7..1c004568c 100644 --- a/Runtime/Graphics/CGraphics.hpp +++ b/Runtime/Graphics/CGraphics.hpp @@ -305,78 +305,17 @@ public: static float GetCroppedViewportUVYMin() { return g_CroppedViewport.x20_uvYMin; } static float GetCroppedViewportUVYMax() { return g_CroppedViewport.x24_uvYMax; } - // static boo::IGraphicsDataFactory::Platform g_BooPlatform; - // static const char* g_BooPlatformName; - // static boo::IGraphicsDataFactory* g_BooFactory; - // static boo::IGraphicsCommandQueue* g_BooMainCommandQueue; - // static boo::ObjToken g_SpareTexture; - static const std::array skCubeBasisMats; - // static void InitializeBoo(boo::IGraphicsDataFactory* factory, boo::IGraphicsCommandQueue* cc, - // const boo::ObjToken& spareTex) { - // g_BooPlatform = factory->platform(); - // g_BooPlatformName = factory->platformName(); - // g_BooFactory = factory; - // g_BooMainCommandQueue = cc; - // g_SpareTexture = spareTex; - // } - // - // static void ShutdownBoo() { - // g_BooFactory = nullptr; - // g_BooMainCommandQueue = nullptr; - // g_SpareTexture.reset(); - // } - // - // static const char* PlatformName() { return g_BooPlatformName; } - - // static void CommitResources(const boo::FactoryCommitFunc& commitFunc __BooTraceArgs) { - // g_BooFactory->commitTransaction(commitFunc __BooTraceArgsUse); - // } - - // static bool g_commitAsLazy; - // static void SetCommitResourcesAsLazy(bool newStatus) { - // if (newStatus != g_commitAsLazy) { - // g_commitAsLazy = newStatus; - // if (!newStatus && g_BooFactory) { - // g_BooFactory->commitPendingTransaction(); - // } - // } - // } - // - // static void CommitResources(const boo::FactoryCommitFunc& commitFunc __BooTraceArgs) { - // CommitResources(commitFunc __BooTraceArgsUse, g_commitAsLazy); - // } - // - // static void CommitResources(const boo::FactoryCommitFunc& commitFunc __BooTraceArgs, bool lazy) { - // if (!g_BooFactory) { - // return; - // } - // if (lazy) { - // g_BooFactory->lazyCommitTransaction(commitFunc __BooTraceArgsUse); - // } else { - // g_BooFactory->commitTransaction(commitFunc __BooTraceArgsUse); - // } - // } - // - // static void SetShaderDataBinding(const boo::ObjToken& binding) { - // g_BooMainCommandQueue->setShaderDataBinding(binding); - // } static void ResolveSpareTexture(const SClipScreenRect& rect, int bindIdx = 0, bool clearDepth = false) { aurora::gfx::resolve_color({rect.x4_left, rect.x8_top, rect.xc_width, rect.x10_height}, bindIdx, clearDepth); - // boo::SWindowRect wrect = {rect.x4_left, rect.x8_top, rect.xc_width, rect.x10_height}; - // g_BooMainCommandQueue->resolveBindTexture(g_SpareTexture, wrect, true, bindIdx, true, false, clearDepth); + } + static void LoadDolphinSpareTexture(int bindIdx, GX::TexMapID id) { + aurora::gfx::bind_color(bindIdx, id); } static void ResolveSpareDepth(const SClipScreenRect& rect, int bindIdx = 0) { aurora::gfx::resolve_depth({rect.x4_left, rect.x8_top, rect.xc_width, rect.x10_height}, bindIdx); - // boo::SWindowRect wrect = {rect.x4_left, rect.x8_top, rect.xc_width, rect.x10_height}; - // g_BooMainCommandQueue->resolveBindTexture(g_SpareTexture, wrect, true, bindIdx, false, true); } - // static void DrawInstances(size_t start, size_t count, size_t instCount, size_t startInst = 0) { - // g_BooMainCommandQueue->drawInstances(start, count, instCount, startInst); - // } - // static void DrawArray(size_t start, size_t count) { g_BooMainCommandQueue->draw(start, count); } - // static void DrawArrayIndexed(size_t start, size_t count) { g_BooMainCommandQueue->drawIndexed(start, count); } static void SetTevStates(EStreamFlags flags) noexcept; static void SetTevOp(ERglTevStage stage, const CTevCombiners::CTevPass& pass); diff --git a/Runtime/MP1/CInGameGuiManager.cpp b/Runtime/MP1/CInGameGuiManager.cpp index 5e4a7fec5..b58eb9901 100644 --- a/Runtime/MP1/CInGameGuiManager.cpp +++ b/Runtime/MP1/CInGameGuiManager.cpp @@ -473,21 +473,15 @@ void CInGameGuiManager::Draw(CStateManager& stateMgr) { // if (!GetIsGameDraw()) // g_Renderer->x318_26_requestRGBA6 = true; if (x1d8_onScreenTexAlpha > 0.f && x1dc_onScreenTexTok.IsLoaded()) { - if (!m_onScreenQuad || m_onScreenQuad->GetTex().GetObj() != x1dc_onScreenTexTok.GetObj()) - m_onScreenQuad.emplace(EFilterType::Blend, x1dc_onScreenTexTok); - - // No depth read/write - // Alpha blend - int w = (CGraphics::GetViewportLeft() + (x1c4_onScreenTex.x4_origin.x - CGraphics::GetViewportWidth()) / 2 + - x1c4_onScreenTex.xc_extent.x) - - x1c4_onScreenTex.x4_origin.x; - int h = (CGraphics::GetViewportTop() + (x1c4_onScreenTex.x4_origin.y - CGraphics::GetViewportHeight()) / 2 - - x1c4_onScreenTex.xc_extent.y) - - x1c4_onScreenTex.x4_origin.y; - zeus::CRectangle rect(x1c4_onScreenTex.x4_origin.x / float(CGraphics::GetViewportWidth()), - x1c4_onScreenTex.x4_origin.y / float(CGraphics::GetViewportHeight()), - w / float(CGraphics::GetViewportWidth()), h / float(CGraphics::GetViewportHeight())); - m_onScreenQuad->draw(zeus::CColor(1.f, x1d8_onScreenTexAlpha), 1.f, rect); + g_Renderer->SetDepthReadWrite(false, false); + g_Renderer->SetBlendMode_AlphaBlended(); + CGraphics::SetTevOp(ERglTevStage::Stage0, CTevCombiners::sTevPass805a5ebc); + CGraphics::SetTevOp(ERglTevStage::Stage1, CTevCombiners::skPassThru); + int w = x1c4_onScreenTex.x4_origin.x; + int h = x1c4_onScreenTex.x4_origin.y; + int x = CGraphics::GetViewportLeft() + (CGraphics::GetViewportWidth() - w) / 2 + x1c4_onScreenTex.xc_extent.x; + int y = CGraphics::GetViewportTop() + (CGraphics::GetViewportHeight() - h) / 2 - x1c4_onScreenTex.xc_extent.y; + CGraphics::Render2D(*x1dc_onScreenTexTok, x, y, w, h, zeus::CColor{1.f, x1d8_onScreenTexAlpha}); } float staticAlpha = 0.f; @@ -517,8 +511,10 @@ void CInGameGuiManager::Draw(CStateManager& stateMgr) { x40_samusReflection->Draw(stateMgr); if (drawVisor) { CGraphics::SetDepthRange(DEPTH_HUD, DEPTH_SCREEN_ACTORS); - if (staticAlpha > 0.f) - m_randomStatic.draw(zeus::CColor(1.f, staticAlpha), 1.f); + if (staticAlpha > 0.f) { + CCameraFilterPass::DrawFilter(EFilterType::Blend, EFilterShape::RandomStatic, zeus::CColor{1.f, staticAlpha}, + nullptr, 1.f); + } x34_samusHud->Draw(stateMgr, x1f4_visorStaticAlpha * (1.f - staticAlpha), x1e0_helmetVisMode, x1ec_hudVisMode != EHudVisMode::Zero, x1e4_enableTargetingManager && !scanVisor); } @@ -552,10 +548,10 @@ void CInGameGuiManager::Draw(CStateManager& stateMgr) { CGraphics::SetDepthRange(DEPTH_NEAR, DEPTH_HUD); x148_model_automapper->SetIsVisible(true); x148_model_automapper->Draw(CGuiWidgetDrawParms(1.f, zeus::skZero3f)); - // ZTest no write + CGraphics::SetDepthWriteMode(true, ERglEnum::GEqual, false); x38_autoMapper->Draw(stateMgr, zeus::CTransform::Translate(0.f, 0.02f, 0.f) * x18c_mapCamXf, mapAlpha * x1f4_visorStaticAlpha * t); - // Zest and write + CGraphics::SetDepthWriteMode(true, ERglEnum::LEqual, true); x148_model_automapper->SetIsVisible(false); } @@ -590,7 +586,7 @@ void CInGameGuiManager::Draw(CStateManager& stateMgr) { dieDur = 6.f; float alpha = zeus::clamp(0.f, stateMgr.GetPlayer().GetDeathTime() / dieDur, 1.f); - m_deathWhiteout.draw(zeus::CColor(1.f, alpha)); + CCameraFilterPass::DrawFilter(EFilterType::Blend, EFilterShape::Fullscreen, zeus::CColor{1.f, alpha}, nullptr, 1.f); float zStart = dieDur - 0.5f - 0.5f - 1.f; float xStart = 0.5f - zStart; @@ -601,24 +597,24 @@ void CInGameGuiManager::Draw(CStateManager& stateMgr) { float colT = 1.f - zeus::clamp(0.f, (stateMgr.GetPlayer().GetDeathTime() - colStart) / 0.5f, 1.f); SClipScreenRect rect(CGraphics::g_Viewport); CGraphics::ResolveSpareTexture(rect); - m_deathBlackout.draw(zeus::skBlack); - float z = 0.5f * (zT * zT * zT * zT * zT * (CGraphics::GetViewportHeight()- 12.f) + 12.f); + CCameraFilterPass::DrawFilter(EFilterType::Blend, EFilterShape::Fullscreen, zeus::skBlack, nullptr, 1.f); + float z = 0.5f * (zT * zT * zT * zT * zT * (CGraphics::GetViewportHeight() - 12.f) + 12.f); float x = 0.5f * (xT * (CGraphics::GetViewportWidth() - 12.f) + 12.f); - const std::array verts{{ - {{-x, 0.f, z}, {0.f, 0.f}}, - {{-x, 0.f, -z}, {0.f, 1.f}}, - {{x, 0.f, z}, {1.f, 0.f}}, - {{x, 0.f, -z}, {1.f, 1.f}}, - }}; + // const std::array verts{{ + // {{-x, 0.f, z}, {0.f, 0.f}}, + // {{-x, 0.f, -z}, {0.f, 1.f}}, + // {{x, 0.f, z}, {1.f, 0.f}}, + // {{x, 0.f, -z}, {1.f, 1.f}}, + // }}; // if (!m_deathRenderTexQuad) // m_deathRenderTexQuad.emplace(EFilterType::Blend, CGraphics::g_SpareTexture.get()); // m_deathRenderTexQuad->drawVerts(zeus::CColor(1.f, colT), verts); - if (!m_deathDotQuad) - m_deathDotQuad.emplace(EFilterType::Multiply, x50_deathDot); - m_deathDotQuad->drawVerts(zeus::CColor(1.f, colT), verts); + // if (!m_deathDotQuad) + // m_deathDotQuad.emplace(EFilterType::Multiply, x50_deathDot); + // m_deathDotQuad->drawVerts(zeus::CColor(1.f, colT), verts); } } } diff --git a/Runtime/MP1/CInGameGuiManager.hpp b/Runtime/MP1/CInGameGuiManager.hpp index acddf45e2..bac2dd31a 100644 --- a/Runtime/MP1/CInGameGuiManager.hpp +++ b/Runtime/MP1/CInGameGuiManager.hpp @@ -88,7 +88,6 @@ private: SOnScreenTex x1c4_onScreenTex; float x1d8_onScreenTexAlpha = 0.f; TLockedToken x1dc_onScreenTexTok; // Used to be heap-allocated - std::optional m_onScreenQuad; EHelmetVisMode x1e0_helmetVisMode; bool x1e4_enableTargetingManager; bool x1e8_enableAutoMapper; @@ -100,12 +99,6 @@ private: bool x1f8_26_deferTransition : 1 = false; bool x1f8_27_exitSaveUI : 1 = true; - std::optional m_deathRenderTexQuad; - std::optional m_deathDotQuad; - CRandomStaticFilter m_randomStatic{EFilterType::Blend}; - CColoredQuadFilter m_deathWhiteout{EFilterType::Blend}; - CColoredQuadFilter m_deathBlackout{EFilterType::Blend}; - static std::vector> LockPauseScreenDependencies(); bool CheckDGRPLoadComplete() const; void BeginStateTransition(EInGameGuiState state, CStateManager& stateMgr); diff --git a/Runtime/MP1/CPlayerVisor.cpp b/Runtime/MP1/CPlayerVisor.cpp index 20ffe4f78..cad374539 100644 --- a/Runtime/MP1/CPlayerVisor.cpp +++ b/Runtime/MP1/CPlayerVisor.cpp @@ -355,33 +355,28 @@ void CPlayerVisor::DrawScanEffect(const CStateManager& mgr, CTargetingManager* t rect.x10_height = int(vpH); CGraphics::ResolveSpareTexture(rect); - x64_scanDim.Draw(); + // TODO hack; figure out why needed + CGraphics::SetCullMode(ERglCullMode::None); + + { + SCOPED_GRAPHICS_DEBUG_GROUP("x64_scanDim Draw", zeus::skMagenta); + x64_scanDim.Draw(); + } g_Renderer->SetViewportOrtho(true, -1.f, 1.f); const zeus::CTransform windowScale = zeus::CTransform::Scale(x48_interpWindowDims.x(), 1.f, x48_interpWindowDims.y()); const zeus::CTransform seventeenScale = zeus::CTransform::Scale(17.f * vpScale, 1.f, 17.f * vpScale); - CGraphics::SetModelMatrix(seventeenScale * windowScale); + const zeus::CTransform mm = seventeenScale * windowScale; + g_Renderer->SetModelMatrix(mm); + CGraphics::LoadDolphinSpareTexture(0, GX::TEXMAP0); - const float uvX0 = float(rect.x4_left) / float(CGraphics::GetViewportWidth()); - const float uvX1 = float(rect.x4_left + rect.xc_width) / float(CGraphics::GetViewportWidth()); - const float uvY0 = float(rect.x8_top) / float(CGraphics::GetViewportHeight()); - const float uvY1 = float(rect.x8_top + rect.x10_height) / float(CGraphics::GetViewportHeight()); - std::array rttVerts{{ - {{-5.f, 0.f, 4.45f}, {uvX0, uvY0}}, - {{5.f, 0.f, 4.45f}, {uvX1, uvY0}}, - {{-5.f, 0.f, -4.45f}, {uvX0, uvY1}}, - {{5.f, 0.f, -4.45f}, {uvX1, uvY1}}, - }}; - // if (CGraphics::g_BooPlatform == boo::IGraphicsDataFactory::Platform::OpenGL) { - // rttVerts[0].m_uv.y() = uvY1; - // rttVerts[1].m_uv.y() = uvY1; - // rttVerts[2].m_uv.y() = uvY0; - // rttVerts[3].m_uv.y() = uvY0; - // } - // x108_newScanPane.drawVerts(zeus::CColor(1.f, transFactor), rttVerts); + if (x108_newScanPane) { + SCOPED_GRAPHICS_DEBUG_GROUP("x108_newScanPane Draw", zeus::skMagenta); + x108_newScanPane->Draw(CModelFlags{5, 0, 7, zeus::CColor{1.f, transFactor}}); + } - // No cull faces + CGraphics::SetCullMode(ERglCullMode::None); zeus::CColor frameColor = zeus::CColor::lerp(g_tweakGuiColors->GetScanFrameInactiveColor(), g_tweakGuiColors->GetScanFrameActiveColor(), x54c_scanFrameColorInterp); @@ -390,7 +385,6 @@ void CPlayerVisor::DrawScanEffect(const CStateManager& mgr, CTargetingManager* t CModelFlags flags(5, 0, 0, frameColor + g_tweakGuiColors->GetScanFrameImpulseColor() * zeus::CColor(x550_scanFrameColorImpulseInterp, x550_scanFrameColorImpulseInterp)); - // TODO flags.m_noCull = true; const zeus::CTransform verticalFlip = zeus::CTransform::Scale(1.f, 1.f, -1.f); const zeus::CTransform horizontalFlip = zeus::CTransform::Scale(-1.f, 1.f, 1.f); @@ -454,7 +448,7 @@ void CPlayerVisor::DrawScanEffect(const CStateManager& mgr, CTargetingManager* t xf0_scanFrameStretchSide->Draw(flags); } - // cull faces + CGraphics::SetCullMode(ERglCullMode::Front); } void CPlayerVisor::DrawXRayEffect(const CStateManager&) { diff --git a/aurora/include/aurora/gfx.hpp b/aurora/include/aurora/gfx.hpp index 07143e997..4f9b0dd05 100644 --- a/aurora/include/aurora/gfx.hpp +++ b/aurora/include/aurora/gfx.hpp @@ -98,6 +98,7 @@ void set_scissor(uint32_t x, uint32_t y, uint32_t w, uint32_t h) noexcept; void resolve_color(const ClipRect& rect, uint32_t bind, bool clear_depth) noexcept; void resolve_depth(const ClipRect& rect, uint32_t bind) noexcept; +void bind_color(u32 bindIdx, GX::TexMapID id) noexcept; void queue_movie_player(const TextureHandle& tex_y, const TextureHandle& tex_u, const TextureHandle& tex_v, float h_pad, float v_pad) noexcept; @@ -106,7 +107,6 @@ TextureHandle new_static_texture_2d(uint32_t width, uint32_t height, uint32_t mi ArrayRef data, zstring_view label) noexcept; TextureHandle new_dynamic_texture_2d(uint32_t width, uint32_t height, uint32_t mips, metaforce::ETexelFormat format, zstring_view label) noexcept; -TextureHandle new_render_texture(uint32_t width, uint32_t height, uint32_t color_bind_count, uint32_t depth_bind_count, - zstring_view label) noexcept; +TextureHandle new_render_texture(uint32_t width, uint32_t height, zstring_view label) noexcept; void write_texture(const TextureHandle& handle, ArrayRef data) noexcept; } // namespace aurora::gfx diff --git a/aurora/lib/aurora.cpp b/aurora/lib/aurora.cpp index d8899d765..d3db4f711 100644 --- a/aurora/lib/aurora.cpp +++ b/aurora/lib/aurora.cpp @@ -300,52 +300,26 @@ void app_run(std::unique_ptr app, Icon icon, int argc, char** argv) }; auto encoder = g_device.CreateCommandEncoder(&encoderDescriptor); gfx::end_frame(encoder); + gfx::render(encoder); { const std::array attachments{ wgpu::RenderPassColorAttachment{ .view = view, - // .resolveTarget = g_frameBufferResolved.view, .loadOp = wgpu::LoadOp::Clear, .storeOp = wgpu::StoreOp::Store, - .clearValue = - { - .r = gfx::gx::g_gxState.clearColor.r(), - .g = gfx::gx::g_gxState.clearColor.g(), - .b = gfx::gx::g_gxState.clearColor.b(), - .a = gfx::gx::g_gxState.clearColor.a(), - }, - }, - }; - const auto depthStencilAttachment = wgpu::RenderPassDepthStencilAttachment{ - .view = g_depthBuffer.view, - .depthLoadOp = wgpu::LoadOp::Clear, - .depthStoreOp = wgpu::StoreOp::Discard, - .clearDepth = 1.f, - }; - auto renderPassDescriptor = wgpu::RenderPassDescriptor{ - .label = "Main render pass", - .colorAttachmentCount = attachments.size(), - .colorAttachments = attachments.data(), - .depthStencilAttachment = &depthStencilAttachment, - }; - auto pass = encoder.BeginRenderPass(&renderPassDescriptor); - gfx::render(pass); - pass.End(); - } - { - const std::array attachments{ - wgpu::RenderPassColorAttachment{ - .view = view, - .loadOp = wgpu::LoadOp::Load, - .storeOp = wgpu::StoreOp::Store, }, }; auto renderPassDescriptor = wgpu::RenderPassDescriptor{ - .label = "ImGui render pass", + .label = "Post render pass", .colorAttachmentCount = attachments.size(), .colorAttachments = attachments.data(), }; auto pass = encoder.BeginRenderPass(&renderPassDescriptor); + // Copy EFB -> XFB (swapchain) + pass.SetPipeline(gpu::g_CopyPipeline); + pass.SetBindGroup(0, gpu::g_CopyBindGroup); + pass.Draw(3); + // Render ImGui imgui::render(pass); pass.End(); } diff --git a/aurora/lib/gfx/common.cpp b/aurora/lib/gfx/common.cpp index a3ca6d4e2..55d6b6b47 100644 --- a/aurora/lib/gfx/common.cpp +++ b/aurora/lib/gfx/common.cpp @@ -123,7 +123,17 @@ static wgpu::SupportedLimits g_cachedLimits; static ShaderState g_state; static PipelineRef g_currentPipeline; -static std::vector g_commands; +using CommandList = std::vector; +struct RenderPass { + u32 resolveTarget = UINT32_MAX; + ClipRect resolveRect; + zeus::CColor clearColor{0.f, 0.f}; + CommandList commands; + bool clear = true; +}; +static std::vector g_renderPasses; +static u32 g_currentRenderPass; +std::vector g_resolvedTextures; static ByteBuffer g_serializedPipelines{}; static u32 g_serializedPipelineCount = 0; @@ -175,27 +185,23 @@ static PipelineRef find_pipeline(ShaderType type, const PipelineConfig& config, return hash; } -static void push_draw_command(ShaderDrawCommand data) { - g_commands.push_back({ - .type = CommandType::Draw, +static inline void push_command(CommandType type, const Command::Data& data) { + g_renderPasses[g_currentRenderPass].commands.push_back({ + .type = type, #ifdef AURORA_GFX_DEBUG_GROUPS .debugGroupStack = g_debugGroupStack, #endif - .data = {.draw = data}, + .data = data, }); } +static void push_draw_command(ShaderDrawCommand data) { push_command(CommandType::Draw, Command::Data{.draw = data}); } + static Command::Data::SetViewportCommand g_cachedViewport; void set_viewport(float left, float top, float width, float height, float znear, float zfar) noexcept { Command::Data::SetViewportCommand cmd{left, top, width, height, znear, zfar}; if (cmd != g_cachedViewport) { - g_commands.push_back({ - .type = CommandType::SetViewport, -#ifdef AURORA_GFX_DEBUG_GROUPS - .debugGroupStack = g_debugGroupStack, -#endif - .data = {.setViewport = cmd}, - }); + push_command(CommandType::SetViewport, Command::Data{.setViewport = cmd}); g_cachedViewport = cmd; } } @@ -203,24 +209,40 @@ static Command::Data::SetScissorCommand g_cachedScissor; void set_scissor(uint32_t x, uint32_t y, uint32_t w, uint32_t h) noexcept { Command::Data::SetScissorCommand cmd{x, y, w, h}; if (cmd != g_cachedScissor) { - g_commands.push_back({ - .type = CommandType::SetScissor, -#ifdef AURORA_GFX_DEBUG_GROUPS - .debugGroupStack = g_debugGroupStack, -#endif - .data = {.setScissor = cmd}, - }); + push_command(CommandType::SetScissor, Command::Data{.setScissor = cmd}); g_cachedScissor = cmd; } } +bool operator==(const wgpu::Extent3D& lhs, const wgpu::Extent3D& rhs) { + return lhs.width == rhs.width && lhs.height == rhs.height && lhs.depthOrArrayLayers == rhs.depthOrArrayLayers; +} + void resolve_color(const ClipRect& rect, uint32_t bind, bool clear_depth) noexcept { - // TODO + if (g_resolvedTextures.size() < bind + 1) { + g_resolvedTextures.resize(bind + 1); + } + const wgpu::Extent3D size{ + .width = static_cast(rect.width), + .height = static_cast(rect.height), + }; + if (!g_resolvedTextures[bind] || g_resolvedTextures[bind].ref->size != size) { + g_resolvedTextures[bind] = new_render_texture(rect.width, rect.height, "Resolved Texture"); + } + auto& currentPass = g_renderPasses[g_currentRenderPass]; + currentPass.resolveTarget = bind; + currentPass.resolveRect = rect; + auto& newPass = g_renderPasses.emplace_back(); + newPass.clearColor = gx::g_gxState.clearColor; + newPass.clear = false; // TODO + ++g_currentRenderPass; } void resolve_depth(const ClipRect& rect, uint32_t bind) noexcept { // TODO } +void bind_color(u32 bindIdx, GX::TexMapID id) noexcept { gx::g_gxState.textures[static_cast(id)] = {bindIdx}; } + void queue_movie_player(const TextureHandle& tex_y, const TextureHandle& tex_u, const TextureHandle& tex_v, float h_pad, float v_pad) noexcept { auto data = movie_player::make_draw_data(g_state.moviePlayer, tex_y, tex_u, tex_v, h_pad, v_pad); @@ -323,13 +345,15 @@ void initialize() { { // Load serialized pipeline cache std::ifstream file("pipeline_cache.bin", std::ios::in | std::ios::binary | std::ios::ate); - const size_t size = file.tellg(); - file.seekg(0, std::ios::beg); - constexpr size_t headerSize = sizeof(g_serializedPipelineCount); - if (size != -1 && size > headerSize) { - g_serializedPipelines.append_zeroes(size - headerSize); - file.read(reinterpret_cast(&g_serializedPipelineCount), headerSize); - file.read(reinterpret_cast(g_serializedPipelines.data()), size - headerSize); + if (file) { + const size_t size = file.tellg(); + file.seekg(0, std::ios::beg); + constexpr size_t headerSize = sizeof(g_serializedPipelineCount); + if (size != -1 && size > headerSize) { + g_serializedPipelines.append_zeroes(size - headerSize); + file.read(reinterpret_cast(&g_serializedPipelineCount), headerSize); + file.read(reinterpret_cast(g_serializedPipelines.data()), size - headerSize); + } } } if (g_serializedPipelineCount > 0) { @@ -390,8 +414,10 @@ void shutdown() { { // Write serialized pipelines to file std::ofstream file("pipeline_cache.bin", std::ios::out | std::ios::trunc | std::ios::binary); - file.write(reinterpret_cast(&g_serializedPipelineCount), sizeof(g_serializedPipelineCount)); - file.write(reinterpret_cast(g_serializedPipelines.data()), g_serializedPipelines.size()); + if (file) { + file.write(reinterpret_cast(&g_serializedPipelineCount), sizeof(g_serializedPipelineCount)); + file.write(reinterpret_cast(g_serializedPipelines.data()), g_serializedPipelines.size()); + } } gx::shutdown(); @@ -440,6 +466,9 @@ void begin_frame() { mapBuffer(g_uniforms, UniformBufferSize); mapBuffer(g_indices, IndexBufferSize); mapBuffer(g_storage, StorageBufferSize); + + g_renderPasses.emplace_back(); + g_currentRenderPass = 0; } // for imgui debug @@ -468,13 +497,80 @@ void end_frame(const wgpu::CommandEncoder& cmd) { map_staging_buffer(); } -void render(const wgpu::RenderPassEncoder& pass) { +void render(wgpu::CommandEncoder& cmd) { + for (u32 i = 0; i < g_renderPasses.size(); ++i) { + const auto& passInfo = g_renderPasses[i]; + bool finalPass = i == g_renderPasses.size() - 1; + if (finalPass && passInfo.resolveTarget != UINT32_MAX) { + Log.report(logvisor::Fatal, FMT_STRING("Final render pass must not have resolve target")); + unreachable(); + } + const std::array attachments{ + wgpu::RenderPassColorAttachment{ + .view = gpu::g_frameBuffer.view, + .resolveTarget = gpu::g_graphicsConfig.msaaSamples > 1 ? gpu::g_frameBufferResolved.view : nullptr, + .loadOp = passInfo.clear ? wgpu::LoadOp::Clear : wgpu::LoadOp::Load, + .storeOp = wgpu::StoreOp::Store, + .clearValue = + { + .r = passInfo.clearColor.r(), + .g = passInfo.clearColor.g(), + .b = passInfo.clearColor.b(), + .a = passInfo.clearColor.a(), + }, + }, + }; + const wgpu::RenderPassDepthStencilAttachment depthStencilAttachment{ + .view = gpu::g_depthBuffer.view, + .depthLoadOp = wgpu::LoadOp::Clear, + .depthStoreOp = wgpu::StoreOp::Discard, + .depthClearValue = 1.f, + }; + const auto label = fmt::format(FMT_STRING("Render pass {}"), i); + const wgpu::RenderPassDescriptor renderPassDescriptor{ + .label = label.c_str(), + .colorAttachmentCount = attachments.size(), + .colorAttachments = attachments.data(), + .depthStencilAttachment = &depthStencilAttachment, + }; + auto pass = cmd.BeginRenderPass(&renderPassDescriptor); + render_pass(pass, i); + pass.End(); + + if (passInfo.resolveTarget != UINT32_MAX) { + wgpu::ImageCopyTexture src{ + .origin = + wgpu::Origin3D{ + .x = static_cast(passInfo.resolveRect.x), + .y = static_cast(passInfo.resolveRect.y), + }, + }; + if (gpu::g_graphicsConfig.msaaSamples > 1) { + src.texture = gpu::g_frameBufferResolved.texture; + } else { + src.texture = gpu::g_frameBuffer.texture; + } + auto& target = g_resolvedTextures[passInfo.resolveTarget]; + const wgpu::ImageCopyTexture dst{ + .texture = target.ref->texture, + }; + const wgpu::Extent3D size{ + .width = static_cast(passInfo.resolveRect.width), + .height = static_cast(passInfo.resolveRect.height), + }; + cmd.CopyTextureToTexture(&src, &dst, &size); + } + } + g_renderPasses.clear(); +} + +void render_pass(const wgpu::RenderPassEncoder& pass, u32 idx) { g_currentPipeline = UINT64_MAX; #ifdef AURORA_GFX_DEBUG_GROUPS std::vector lastDebugGroupStack; #endif - for (const auto& cmd : g_commands) { + for (const auto& cmd : g_renderPasses[idx].commands) { #ifdef AURORA_GFX_DEBUG_GROUPS { size_t firstDiff = lastDebugGroupStack.size(); @@ -524,8 +620,6 @@ void render(const wgpu::RenderPassEncoder& pass) { pass.PopDebugGroup(); } #endif - - g_commands.clear(); } bool bind_pipeline(PipelineRef ref, const wgpu::RenderPassEncoder& pass) { diff --git a/aurora/lib/gfx/common.hpp b/aurora/lib/gfx/common.hpp index 6fed9810c..cd6a5a216 100644 --- a/aurora/lib/gfx/common.hpp +++ b/aurora/lib/gfx/common.hpp @@ -125,6 +125,8 @@ extern wgpu::Buffer g_uniformBuffer; extern wgpu::Buffer g_indexBuffer; extern wgpu::Buffer g_storageBuffer; extern size_t g_staticStorageLastSize; +// TODO this is a bad place for this... +extern std::vector g_resolvedTextures; struct TextureRef { wgpu::Texture texture; @@ -168,7 +170,8 @@ void shutdown(); void begin_frame(); void end_frame(const wgpu::CommandEncoder& cmd); -void render(const wgpu::RenderPassEncoder& pass); +void render(wgpu::CommandEncoder& cmd); +void render_pass(const wgpu::RenderPassEncoder& pass, u32 idx); void map_staging_buffer(); Range push_verts(const uint8_t* data, size_t length); diff --git a/aurora/lib/gfx/gx.cpp b/aurora/lib/gfx/gx.cpp index 0bf56c823..fb7e8aaec 100644 --- a/aurora/lib/gfx/gx.cpp +++ b/aurora/lib/gfx/gx.cpp @@ -495,6 +495,80 @@ void populate_pipeline_config(PipelineConfig& config, GX::Primitive primitive) n config.shaderConfig.indexedAttributeCount = std::count_if(config.shaderConfig.vtxAttrs.begin(), config.shaderConfig.vtxAttrs.end(), [](const auto type) { return type == GX::INDEX8 || type == GX::INDEX16; }); + for (u8 i = 0; i < MaxTextures; ++i) { + const auto& bind = g_gxState.textures[i]; + bool hasAlpha = false; + // TODO check resolved fmt + if (bind.handle) { + wgpu::TextureFormat format = bind.handle.ref->format; + switch (format) { + case wgpu::TextureFormat::R8Unorm: + case wgpu::TextureFormat::R8Snorm: + case wgpu::TextureFormat::R8Uint: + case wgpu::TextureFormat::R8Sint: + case wgpu::TextureFormat::R16Uint: + case wgpu::TextureFormat::R16Sint: + case wgpu::TextureFormat::R16Float: + case wgpu::TextureFormat::RG8Unorm: + case wgpu::TextureFormat::RG8Snorm: + case wgpu::TextureFormat::RG8Uint: + case wgpu::TextureFormat::RG8Sint: + case wgpu::TextureFormat::R32Float: + case wgpu::TextureFormat::R32Uint: + case wgpu::TextureFormat::R32Sint: + case wgpu::TextureFormat::RG16Uint: + case wgpu::TextureFormat::RG16Sint: + case wgpu::TextureFormat::RG16Float: + case wgpu::TextureFormat::RG11B10Ufloat: + case wgpu::TextureFormat::RGB9E5Ufloat: + case wgpu::TextureFormat::RG32Float: + case wgpu::TextureFormat::RG32Uint: + case wgpu::TextureFormat::RG32Sint: + case wgpu::TextureFormat::BC4RUnorm: + case wgpu::TextureFormat::BC4RSnorm: + case wgpu::TextureFormat::BC5RGUnorm: + case wgpu::TextureFormat::BC5RGSnorm: + case wgpu::TextureFormat::BC6HRGBUfloat: + case wgpu::TextureFormat::BC6HRGBFloat: + case wgpu::TextureFormat::ETC2RGB8Unorm: + case wgpu::TextureFormat::ETC2RGB8UnormSrgb: + hasAlpha = false; + break; + case wgpu::TextureFormat::RGBA8Unorm: + case wgpu::TextureFormat::RGBA8UnormSrgb: + case wgpu::TextureFormat::RGBA8Snorm: + case wgpu::TextureFormat::RGBA8Uint: + case wgpu::TextureFormat::RGBA8Sint: + case wgpu::TextureFormat::BGRA8Unorm: + case wgpu::TextureFormat::BGRA8UnormSrgb: + case wgpu::TextureFormat::RGB10A2Unorm: + case wgpu::TextureFormat::RGBA16Uint: + case wgpu::TextureFormat::RGBA16Sint: + case wgpu::TextureFormat::RGBA16Float: + case wgpu::TextureFormat::RGBA32Float: + case wgpu::TextureFormat::RGBA32Uint: + case wgpu::TextureFormat::RGBA32Sint: + case wgpu::TextureFormat::BC1RGBAUnorm: + case wgpu::TextureFormat::BC1RGBAUnormSrgb: + case wgpu::TextureFormat::BC2RGBAUnorm: + case wgpu::TextureFormat::BC2RGBAUnormSrgb: + case wgpu::TextureFormat::BC3RGBAUnorm: + case wgpu::TextureFormat::BC3RGBAUnormSrgb: + case wgpu::TextureFormat::BC7RGBAUnorm: + case wgpu::TextureFormat::BC7RGBAUnormSrgb: + case wgpu::TextureFormat::ETC2RGB8A1Unorm: + case wgpu::TextureFormat::ETC2RGB8A1UnormSrgb: + case wgpu::TextureFormat::ETC2RGBA8Unorm: + case wgpu::TextureFormat::ETC2RGBA8UnormSrgb: + hasAlpha = true; + break; + default: + Log.report(logvisor::Fatal, FMT_STRING("Unknown texture format {}"), format); + unreachable(); + } + } + config.shaderConfig.texHasAlpha[i] = hasAlpha; + } config = { .shaderConfig = config.shaderConfig, .primitive = primitive, @@ -681,10 +755,17 @@ GXBindGroups build_bind_groups(const ShaderInfo& info, const ShaderConfig& confi .binding = i, .sampler = sampler_ref(tex.get_descriptor()), }; - textureEntries[i] = { - .binding = i, - .textureView = tex.handle.ref->view, - }; + if (tex.handle) { + textureEntries[i] = { + .binding = i, + .textureView = tex.handle.ref->view, + }; + } else if (tex.resolvedBindIdx != UINT32_MAX) { + textureEntries[i] = { + .binding = i, + .textureView = g_resolvedTextures[tex.resolvedBindIdx].ref->view, + }; + } i++; } return { diff --git a/aurora/lib/gfx/gx.hpp b/aurora/lib/gfx/gx.hpp index 4ce516de0..af7d31285 100644 --- a/aurora/lib/gfx/gx.hpp +++ b/aurora/lib/gfx/gx.hpp @@ -56,15 +56,20 @@ struct TevStage { static_assert(std::has_unique_object_representations_v); struct TextureBind { aurora::gfx::TextureHandle handle; - metaforce::EClampMode clampMode; - float lod; + metaforce::EClampMode clampMode = metaforce::EClampMode::Repeat; + float lod = 0.f; + u32 resolvedBindIdx = UINT32_MAX; TextureBind() noexcept = default; + TextureBind(u32 resolvedBindIdx) noexcept : resolvedBindIdx(resolvedBindIdx) {} TextureBind(aurora::gfx::TextureHandle handle, metaforce::EClampMode clampMode, float lod) noexcept : handle(std::move(handle)), clampMode(clampMode), lod(lod) {} - void reset() noexcept { handle.reset(); }; + void reset() noexcept { + handle.reset(); + resolvedBindIdx = UINT32_MAX; + }; [[nodiscard]] wgpu::SamplerDescriptor get_descriptor() const noexcept; - operator bool() const noexcept { return handle; } + operator bool() const noexcept { return handle || resolvedBindIdx != UINT32_MAX; } }; // For shader generation struct ColorChannelConfig { @@ -182,11 +187,12 @@ struct ShaderConfig { std::array tcgs; AlphaCompare alphaCompare; u32 indexedAttributeCount = 0; + std::array texHasAlpha; bool operator==(const ShaderConfig&) const = default; }; static_assert(std::has_unique_object_representations_v); -constexpr u32 GXPipelineConfigVersion = 1; +constexpr u32 GXPipelineConfigVersion = 2; struct PipelineConfig { u32 version = GXPipelineConfigVersion; ShaderConfig shaderConfig; diff --git a/aurora/lib/gfx/gx_shader.cpp b/aurora/lib/gfx/gx_shader.cpp index bf5d4390b..2591dcd42 100644 --- a/aurora/lib/gfx/gx_shader.cpp +++ b/aurora/lib/gfx/gx_shader.cpp @@ -6,6 +6,7 @@ #include constexpr bool EnableNormalVisualization = false; +constexpr bool EnableDebugPrints = true; namespace aurora::gfx::gx { using namespace fmt::literals; @@ -119,6 +120,7 @@ static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const Sha unreachable(); } const auto swap = config.tevSwapTable[stage.tevSwapTex]; + // TODO check for CH_ALPHA + config.texHasAlpha return fmt::format(FMT_STRING("sampled{}.{}{}{}"), stage.texMapId, chan_comp(swap.red), chan_comp(swap.green), chan_comp(swap.blue)); } @@ -131,6 +133,9 @@ static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const Sha unreachable(); } const auto swap = config.tevSwapTable[stage.tevSwapTex]; + if (swap.alpha == GX::CH_ALPHA && !config.texHasAlpha[stage.texMapId]) { + return "1.0"; + } return fmt::format(FMT_STRING("sampled{}.{}"), stage.texMapId, chan_comp(swap.alpha)); } case GX::CC_RASC: { @@ -305,6 +310,9 @@ static std::string alpha_arg_reg(GX::TevAlphaArg arg, size_t stageIdx, const Sha unreachable(); } const auto swap = config.tevSwapTable[stage.tevSwapTex]; + if (swap.alpha == GX::CH_ALPHA && !config.texHasAlpha[stage.texMapId]) { + return "1.0"; + } return fmt::format(FMT_STRING("sampled{}.{}"), stage.texMapId, chan_comp(swap.alpha)); } case GX::CA_RASA: { @@ -597,53 +605,60 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in return it->second.first; } - Log.report(logvisor::Info, FMT_STRING("Shader config (hash {:x}):"), hash); - - { - for (int i = 0; i < config.tevStageCount; ++i) { - const auto& stage = config.tevStages[i]; - Log.report(logvisor::Info, FMT_STRING(" tevStages[{}]:"), i); - Log.report(logvisor::Info, FMT_STRING(" color_a: {}"), stage.colorPass.a); - Log.report(logvisor::Info, FMT_STRING(" color_b: {}"), stage.colorPass.b); - Log.report(logvisor::Info, FMT_STRING(" color_c: {}"), stage.colorPass.c); - Log.report(logvisor::Info, FMT_STRING(" color_d: {}"), stage.colorPass.d); - Log.report(logvisor::Info, FMT_STRING(" alpha_a: {}"), stage.alphaPass.a); - Log.report(logvisor::Info, FMT_STRING(" alpha_b: {}"), stage.alphaPass.b); - Log.report(logvisor::Info, FMT_STRING(" alpha_c: {}"), stage.alphaPass.c); - Log.report(logvisor::Info, FMT_STRING(" alpha_d: {}"), stage.alphaPass.d); - Log.report(logvisor::Info, FMT_STRING(" color_op_clamp: {}"), stage.colorOp.clamp); - Log.report(logvisor::Info, FMT_STRING(" color_op_op: {}"), stage.colorOp.op); - Log.report(logvisor::Info, FMT_STRING(" color_op_bias: {}"), stage.colorOp.bias); - Log.report(logvisor::Info, FMT_STRING(" color_op_scale: {}"), stage.colorOp.scale); - Log.report(logvisor::Info, FMT_STRING(" color_op_reg_id: {}"), stage.colorOp.outReg); - Log.report(logvisor::Info, FMT_STRING(" alpha_op_clamp: {}"), stage.alphaOp.clamp); - Log.report(logvisor::Info, FMT_STRING(" alpha_op_op: {}"), stage.alphaOp.op); - Log.report(logvisor::Info, FMT_STRING(" alpha_op_bias: {}"), stage.alphaOp.bias); - Log.report(logvisor::Info, FMT_STRING(" alpha_op_scale: {}"), stage.alphaOp.scale); - Log.report(logvisor::Info, FMT_STRING(" alpha_op_reg_id: {}"), stage.alphaOp.outReg); - Log.report(logvisor::Info, FMT_STRING(" kc_sel: {}"), stage.kcSel); - Log.report(logvisor::Info, FMT_STRING(" ka_sel: {}"), stage.kaSel); - Log.report(logvisor::Info, FMT_STRING(" texCoordId: {}"), stage.texCoordId); - Log.report(logvisor::Info, FMT_STRING(" texMapId: {}"), stage.texMapId); - Log.report(logvisor::Info, FMT_STRING(" channelId: {}"), stage.channelId); - } - for (int i = 0; i < config.colorChannels.size(); ++i) { - const auto& chan = config.colorChannels[i]; - Log.report(logvisor::Info, FMT_STRING(" colorChannels[{}]: enabled {} mat {} amb {}"), i, chan.lightingEnabled, - chan.matSrc, chan.ambSrc); - } - for (int i = 0; i < config.tcgs.size(); ++i) { - const auto& tcg = config.tcgs[i]; - if (tcg.src != GX::MAX_TEXGENSRC) { - Log.report(logvisor::Info, FMT_STRING(" tcg[{}]: src {} mtx {} post {} type {} norm {}"), i, tcg.src, tcg.mtx, - tcg.postMtx, tcg.type, tcg.normalize); + if (EnableDebugPrints) { + Log.report(logvisor::Info, FMT_STRING("Shader config (hash {:x}):"), hash); + { + for (int i = 0; i < config.tevStageCount; ++i) { + const auto& stage = config.tevStages[i]; + Log.report(logvisor::Info, FMT_STRING(" tevStages[{}]:"), i); + Log.report(logvisor::Info, FMT_STRING(" color_a: {}"), stage.colorPass.a); + Log.report(logvisor::Info, FMT_STRING(" color_b: {}"), stage.colorPass.b); + Log.report(logvisor::Info, FMT_STRING(" color_c: {}"), stage.colorPass.c); + Log.report(logvisor::Info, FMT_STRING(" color_d: {}"), stage.colorPass.d); + Log.report(logvisor::Info, FMT_STRING(" alpha_a: {}"), stage.alphaPass.a); + Log.report(logvisor::Info, FMT_STRING(" alpha_b: {}"), stage.alphaPass.b); + Log.report(logvisor::Info, FMT_STRING(" alpha_c: {}"), stage.alphaPass.c); + Log.report(logvisor::Info, FMT_STRING(" alpha_d: {}"), stage.alphaPass.d); + Log.report(logvisor::Info, FMT_STRING(" color_op_clamp: {}"), stage.colorOp.clamp); + Log.report(logvisor::Info, FMT_STRING(" color_op_op: {}"), stage.colorOp.op); + Log.report(logvisor::Info, FMT_STRING(" color_op_bias: {}"), stage.colorOp.bias); + Log.report(logvisor::Info, FMT_STRING(" color_op_scale: {}"), stage.colorOp.scale); + Log.report(logvisor::Info, FMT_STRING(" color_op_reg_id: {}"), stage.colorOp.outReg); + Log.report(logvisor::Info, FMT_STRING(" alpha_op_clamp: {}"), stage.alphaOp.clamp); + Log.report(logvisor::Info, FMT_STRING(" alpha_op_op: {}"), stage.alphaOp.op); + Log.report(logvisor::Info, FMT_STRING(" alpha_op_bias: {}"), stage.alphaOp.bias); + Log.report(logvisor::Info, FMT_STRING(" alpha_op_scale: {}"), stage.alphaOp.scale); + Log.report(logvisor::Info, FMT_STRING(" alpha_op_reg_id: {}"), stage.alphaOp.outReg); + Log.report(logvisor::Info, FMT_STRING(" kc_sel: {}"), stage.kcSel); + Log.report(logvisor::Info, FMT_STRING(" ka_sel: {}"), stage.kaSel); + Log.report(logvisor::Info, FMT_STRING(" texCoordId: {}"), stage.texCoordId); + Log.report(logvisor::Info, FMT_STRING(" texMapId: {}"), stage.texMapId); + Log.report(logvisor::Info, FMT_STRING(" channelId: {}"), stage.channelId); } + for (int i = 0; i < config.colorChannels.size(); ++i) { + const auto& chan = config.colorChannels[i]; + Log.report(logvisor::Info, FMT_STRING(" colorChannels[{}]: enabled {} mat {} amb {}"), i, chan.lightingEnabled, + chan.matSrc, chan.ambSrc); + } + for (int i = 0; i < config.tcgs.size(); ++i) { + const auto& tcg = config.tcgs[i]; + if (tcg.src != GX::MAX_TEXGENSRC) { + Log.report(logvisor::Info, FMT_STRING(" tcg[{}]: src {} mtx {} post {} type {} norm {}"), i, tcg.src, + tcg.mtx, tcg.postMtx, tcg.type, tcg.normalize); + } + } + Log.report(logvisor::Info, FMT_STRING(" alphaCompare: comp0 {} ref0 {} op {} comp1 {} ref1 {}"), + config.alphaCompare.comp0, config.alphaCompare.ref0, config.alphaCompare.op, config.alphaCompare.comp1, + config.alphaCompare.ref1); + Log.report(logvisor::Info, FMT_STRING(" indexedAttributeCount: {}"), config.indexedAttributeCount); + Log.report(logvisor::Info, FMT_STRING(" fogType: {}"), config.fogType); + std::string hasAlphaArr; + for (int i = 0; i < config.texHasAlpha.size(); ++i) { + if (i != 0) hasAlphaArr += ", "; + hasAlphaArr += config.texHasAlpha[i] ? "Y" : "N"; + } + Log.report(logvisor::Info, FMT_STRING(" texHasAlpha: [{}]"), hasAlphaArr); } - Log.report(logvisor::Info, FMT_STRING(" alphaCompare: comp0 {} ref0 {} op {} comp1 {} ref1 {}"), - config.alphaCompare.comp0, config.alphaCompare.ref0, config.alphaCompare.op, config.alphaCompare.comp1, - config.alphaCompare.ref1); - Log.report(logvisor::Info, FMT_STRING(" indexedAttributeCount: {}"), config.indexedAttributeCount); - Log.report(logvisor::Info, FMT_STRING(" fogType: {}"), config.fogType); } std::string uniformPre; @@ -912,8 +927,15 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in i, postMtxIdx); } vtxXfrAttrs += fmt::format(FMT_STRING("\n out.tex{0}_uv = tc{0}_proj.xy;"), i); + std::string uvIn; + // FIXME terrible hack to flip Y for render textures + if (config.texHasAlpha[i]) { + uvIn = fmt::format(FMT_STRING("in.tex{0}_uv"), i); + } else { + uvIn = fmt::format(FMT_STRING("vec2(in.tex{0}_uv.x, -in.tex{0}_uv.y)"), i); + } fragmentFnPre += fmt::format( - FMT_STRING("\n var sampled{0} = textureSampleBias(tex{0}, tex{0}_samp, in.tex{0}_uv, ubuf.tex{0}_lod);"), i); + FMT_STRING("\n var sampled{0} = textureSampleBias(tex{0}, tex{0}_samp, {1}, ubuf.tex{0}_lod);"), i, uvIn); } for (int i = 0; i < info.usesTexMtx.size(); ++i) { if (info.usesTexMtx.test(i)) { @@ -1052,7 +1074,9 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4 {{ "vtxOutAttrs"_a = vtxOutAttrs, "vtxInAttrs"_a = vtxInAttrs, "vtxXfrAttrs"_a = vtxXfrAttrs, "fragmentFn"_a = fragmentFn, "fragmentFnPre"_a = fragmentFnPre, "vtxXfrAttrsPre"_a = vtxXfrAttrsPre, "uniformBindings"_a = uniformBindings, "uniformPre"_a = uniformPre); - Log.report(logvisor::Info, FMT_STRING("Generated shader: {}"), shaderSource); + if (EnableDebugPrints) { + Log.report(logvisor::Info, FMT_STRING("Generated shader: {}"), shaderSource); + } wgpu::ShaderModuleWGSLDescriptor wgslDescriptor{}; wgslDescriptor.source = shaderSource.c_str(); diff --git a/aurora/lib/gfx/texture.cpp b/aurora/lib/gfx/texture.cpp index bc583448b..65d701e42 100644 --- a/aurora/lib/gfx/texture.cpp +++ b/aurora/lib/gfx/texture.cpp @@ -113,9 +113,30 @@ TextureHandle new_dynamic_texture_2d(uint32_t width, uint32_t height, uint32_t m return {std::make_shared(std::move(texture), std::move(textureView), size, wgpuFormat, mips, format)}; } -TextureHandle new_render_texture(uint32_t width, uint32_t height, uint32_t color_bind_count, uint32_t depth_bind_count, - zstring_view label) noexcept { - return {}; // TODO +TextureHandle new_render_texture(uint32_t width, uint32_t height, zstring_view label) noexcept { + const auto wgpuFormat = gpu::g_graphicsConfig.colorFormat; + const auto size = wgpu::Extent3D{ + .width = width, + .height = height, + }; + const auto textureDescriptor = wgpu::TextureDescriptor{ + .label = label.c_str(), + .usage = wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::CopyDst, + .size = size, + .format = wgpuFormat, + .mipLevelCount = 1, + }; + const auto viewLabel = fmt::format(FMT_STRING("{} view"), label); + const auto textureViewDescriptor = wgpu::TextureViewDescriptor{ + .label = viewLabel.c_str(), + .format = wgpuFormat, + .dimension = wgpu::TextureViewDimension::e2D, + .mipLevelCount = 1, + }; + auto texture = g_device.CreateTexture(&textureDescriptor); + auto textureView = texture.CreateView(&textureViewDescriptor); + return {std::make_shared(std::move(texture), std::move(textureView), size, wgpuFormat, 1, + metaforce::ETexelFormat::Invalid)}; } // TODO accept mip/layer parameters diff --git a/aurora/lib/gpu.cpp b/aurora/lib/gpu.cpp index e45ea19de..ae7f9edb5 100644 --- a/aurora/lib/gpu.cpp +++ b/aurora/lib/gpu.cpp @@ -28,12 +28,17 @@ TextureWithSampler g_frameBuffer; TextureWithSampler g_frameBufferResolved; TextureWithSampler g_depthBuffer; +// EFB -> XFB copy pipeline +static wgpu::BindGroupLayout g_CopyBindGroupLayout; +wgpu::RenderPipeline g_CopyPipeline; +wgpu::BindGroup g_CopyBindGroup; + static std::unique_ptr g_Instance; static dawn::native::Adapter g_Adapter; static wgpu::AdapterProperties g_AdapterProperties; static std::unique_ptr g_BackendBinding; -static TextureWithSampler create_render_texture(bool multisampled) { +TextureWithSampler create_render_texture(bool multisampled) { const auto size = wgpu::Extent3D{ .width = g_graphicsConfig.width, .height = g_graphicsConfig.height, @@ -45,7 +50,7 @@ static TextureWithSampler create_render_texture(bool multisampled) { } const auto textureDescriptor = wgpu::TextureDescriptor{ .label = "Render texture", - .usage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::TextureBinding, + .usage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst, .size = size, .format = format, .sampleCount = sampleCount, @@ -107,6 +112,119 @@ static TextureWithSampler create_depth_texture() { }; } +void create_copy_pipeline() { + wgpu::ShaderModuleWGSLDescriptor sourceDescriptor{}; + sourceDescriptor.source = R"""( +@group(0) @binding(0) +var efb_sampler: sampler; +@group(0) @binding(1) +var efb_texture: texture_2d; + +struct VertexOutput { + @builtin(position) pos: vec4, + @location(0) uv: vec2, +}; + +var pos: array, 3> = array, 3>( + vec2(-1.0, 1.0), + vec2(-1.0, -3.0), + vec2(3.0, 1.0), +); +var uvs: array, 3> = array, 3>( + vec2(0.0, 0.0), + vec2(0.0, 2.0), + vec2(2.0, 0.0), +); + +@stage(vertex) +fn vs_main(@builtin(vertex_index) vtxIdx: u32) -> VertexOutput { + var out: VertexOutput; + out.pos = vec4(pos[vtxIdx], 0.0, 1.0); + out.uv = uvs[vtxIdx]; + return out; +} + +@stage(fragment) +fn fs_main(in: VertexOutput) -> @location(0) vec4 { + return textureSample(efb_texture, efb_sampler, in.uv); +} +)"""; + const wgpu::ShaderModuleDescriptor moduleDescriptor{ + .nextInChain = &sourceDescriptor, + .label = "XFB Copy Module", + }; + auto module = g_device.CreateShaderModule(&moduleDescriptor); + const std::array colorTargets{ + wgpu::ColorTargetState{ + .format = g_graphicsConfig.colorFormat, + }, + }; + const wgpu::FragmentState fragmentState{ + .module = module, + .entryPoint = "fs_main", + .targetCount = colorTargets.size(), + .targets = colorTargets.data(), + }; + const std::array bindGroupLayoutEntries{ + wgpu::BindGroupLayoutEntry{ + .binding = 0, + .visibility = wgpu::ShaderStage::Fragment, + .sampler = + wgpu::SamplerBindingLayout{ + .type = wgpu::SamplerBindingType::Filtering, + }, + }, + wgpu::BindGroupLayoutEntry{ + .binding = 1, + .visibility = wgpu::ShaderStage::Fragment, + .texture = + wgpu::TextureBindingLayout{ + .sampleType = wgpu::TextureSampleType::Float, + .viewDimension = wgpu::TextureViewDimension::e2D, + }, + }, + }; + const wgpu::BindGroupLayoutDescriptor bindGroupLayoutDescriptor{ + .entryCount = bindGroupLayoutEntries.size(), + .entries = bindGroupLayoutEntries.data(), + }; + g_CopyBindGroupLayout = g_device.CreateBindGroupLayout(&bindGroupLayoutDescriptor); + const wgpu::PipelineLayoutDescriptor layoutDescriptor{ + .bindGroupLayoutCount = 1, + .bindGroupLayouts = &g_CopyBindGroupLayout, + }; + auto pipelineLayout = g_device.CreatePipelineLayout(&layoutDescriptor); + const wgpu::RenderPipelineDescriptor pipelineDescriptor{ + .layout = pipelineLayout, + .vertex = + wgpu::VertexState{ + .module = module, + .entryPoint = "vs_main", + }, + .fragment = &fragmentState, + }; + g_CopyPipeline = g_device.CreateRenderPipeline(&pipelineDescriptor); +} + +void create_copy_bind_group() { + const std::array bindGroupEntries{ + wgpu::BindGroupEntry{ + .binding = 0, + .sampler = g_graphicsConfig.msaaSamples > 1 ? gpu::g_frameBufferResolved.sampler : gpu::g_frameBuffer.sampler, + }, + wgpu::BindGroupEntry{ + .binding = 1, + .textureView = g_graphicsConfig.msaaSamples > 1 ? gpu::g_frameBufferResolved.view : gpu::g_frameBuffer.view, + }, + }; + const wgpu::BindGroupDescriptor bindGroupDescriptor{ + .layout = g_CopyBindGroupLayout, + .entryCount = bindGroupEntries.size(), + .entries = bindGroupEntries.data(), + }; + g_CopyBindGroup = g_device.CreateBindGroup(&bindGroupDescriptor); +} + static void error_callback(WGPUErrorType type, char const* message, void* userdata) { Log.report(logvisor::Fatal, FMT_STRING("Dawn error {}: {}"), magic_enum::enum_name(static_cast(type)), message); @@ -215,9 +333,10 @@ void initialize(SDL_Window* window) { .height = size.fb_height, .colorFormat = swapChainFormat, .depthFormat = wgpu::TextureFormat::Depth32Float, - .msaaSamples = 1, // TODO 4 + .msaaSamples = 4, .textureAnistropy = 16, }; + create_copy_pipeline(); resize_swapchain(size.fb_width, size.fb_height); g_windowSize = size; } @@ -241,5 +360,6 @@ void resize_swapchain(uint32_t width, uint32_t height) { g_frameBuffer = create_render_texture(true); g_frameBufferResolved = create_render_texture(false); g_depthBuffer = create_depth_texture(); + create_copy_bind_group(); } } // namespace aurora::gpu diff --git a/aurora/lib/gpu.hpp b/aurora/lib/gpu.hpp index 8704cb13d..f3df6194e 100644 --- a/aurora/lib/gpu.hpp +++ b/aurora/lib/gpu.hpp @@ -48,10 +48,13 @@ extern GraphicsConfig g_graphicsConfig; extern TextureWithSampler g_frameBuffer; extern TextureWithSampler g_frameBufferResolved; extern TextureWithSampler g_depthBuffer; +extern wgpu::RenderPipeline g_CopyPipeline; +extern wgpu::BindGroup g_CopyBindGroup; void initialize(SDL_Window* window); void shutdown(); void resize_swapchain(uint32_t width, uint32_t height); +TextureWithSampler create_render_texture(bool multisampled); } // namespace aurora::gpu namespace aurora::gpu::utils {