diff --git a/Runtime/Graphics/CGX.hpp b/Runtime/Graphics/CGX.hpp index 4e8ed6b94..69fc6d0fa 100644 --- a/Runtime/Graphics/CGX.hpp +++ b/Runtime/Graphics/CGX.hpp @@ -116,7 +116,7 @@ static inline void SetAlphaCompare(GX::Compare comp0, u8 ref0, GX::AlphaOp op, G u32 flags = ref1 << 17 | (comp1 & 7) << 14 | (op & 7) << 11 | ref0 << 3 | (comp0 & 7); if (flags != sGXState.x248_alphaCompare) { sGXState.x248_alphaCompare = flags; - GXSetAlphaCompare(comp0, ref0 / 255.f, op, comp1, ref1 / 255.f); + GXSetAlphaCompare(comp0, ref0, op, comp1, ref1); // GXSetZCompLoc(comp0 == GX::ALWAYS); } } diff --git a/Runtime/Graphics/CGraphics.hpp b/Runtime/Graphics/CGraphics.hpp index 04ed49aae..acdd3c6b7 100644 --- a/Runtime/Graphics/CGraphics.hpp +++ b/Runtime/Graphics/CGraphics.hpp @@ -104,6 +104,31 @@ enum class ERglEnum : std::underlying_type_t { using ERglLight = u8; +enum class ERglTexOffset : std::underlying_type_t { + Zero = GX::TO_ZERO, + Sixteenth = GX::TO_SIXTEENTH, + Eighth = GX::TO_EIGHTH, + Fourth = GX::TO_FOURTH, + Half = GX::TO_HALF, + One = GX::TO_ONE, +}; + +enum class ERglFogMode : std::underlying_type_t { + None = GX::FOG_NONE, + + PerspLin = GX::FOG_PERSP_LIN, + PerspExp = GX::FOG_PERSP_EXP, + PerspExp2 = GX::FOG_ORTHO_EXP2, + PerspRevExp = GX::FOG_PERSP_REVEXP, + PerspRevExp2 = GX::FOG_PERSP_REVEXP2, + + OrthoLin = GX::FOG_ORTHO_LIN, + OrthoExp = GX::FOG_ORTHO_EXP, + OrthoExp2 = GX::FOG_ORTHO_EXP2, + OrthoRevExp = GX::FOG_ORTHO_REVEXP, + OrthoRevExp2 = GX::FOG_ORTHO_REVEXP2, +}; + struct SViewport { u32 x0_left; u32 x4_top; @@ -371,6 +396,7 @@ public: static void FullRender(); static void DrawPrimitive(GX::Primitive primitive, const zeus::CVector3f* pos, const zeus::CVector3f& normal, const zeus::CColor& col, s32 numVerts); + static void SetLineWidth(float width, ERglTexOffset offs); }; template diff --git a/Runtime/Graphics/CLineRenderer.hpp b/Runtime/Graphics/CLineRenderer.hpp index 015ee205d..08ea80522 100644 --- a/Runtime/Graphics/CLineRenderer.hpp +++ b/Runtime/Graphics/CLineRenderer.hpp @@ -17,22 +17,6 @@ class CLineRenderer { public: enum class EPrimitiveMode { Lines, LineStrip, LineLoop }; - struct SDrawVertTex { - zeus::CVector4f pos; - zeus::CColor color; - zeus::CVector2f uv; - }; - - struct SDrawVertNoTex { - zeus::CVector4f pos; - zeus::CColor color; - }; - - struct SDrawUniform { - zeus::CColor moduColor; - CFogState fog; - }; - private: EPrimitiveMode m_mode; u32 m_maxVerts; diff --git a/Runtime/Graphics/GX.hpp b/Runtime/Graphics/GX.hpp index 1087407d5..aadc0f653 100644 --- a/Runtime/Graphics/GX.hpp +++ b/Runtime/Graphics/GX.hpp @@ -104,7 +104,7 @@ enum TevKColorID { MAX_KCOLOR, }; -enum TevKColorSel : uint8_t { +enum TevKColorSel { TEV_KCSEL_8_8 = 0x00, TEV_KCSEL_7_8 = 0x01, TEV_KCSEL_6_8 = 0x02, @@ -362,7 +362,7 @@ enum ChannelID { COLOR_NULL = 0xff }; -enum BlendMode : uint8_t { +enum BlendMode { BM_NONE, BM_BLEND, BM_LOGIC, @@ -370,7 +370,7 @@ enum BlendMode : uint8_t { MAX_BLENDMODE, }; -enum LogicOp : uint8_t { +enum LogicOp { LO_CLEAR, LO_AND, LO_REVAND, @@ -389,7 +389,7 @@ enum LogicOp : uint8_t { LO_SET }; -enum AlphaOp : uint8_t { +enum AlphaOp { AOP_AND, AOP_OR, AOP_XOR, @@ -715,8 +715,7 @@ void GXSetZMode(GXBool compare_enable, GX::Compare func, GXBool update_enable) n void GXSetTevColor(GX::TevRegID id, const GXColor& color) noexcept; void GXSetTevKColor(GX::TevKColorID id, const GXColor& color) noexcept; void GXSetAlphaUpdate(GXBool enabled) noexcept; -// Originally u8 instead of float -void GXSetDstAlpha(GXBool enabled, float value) noexcept; +void GXSetDstAlpha(GXBool enabled, u8 value) noexcept; void GXSetCopyClear(const GXColor& color, float depth) noexcept; void GXSetTevOrder(GX::TevStageID id, GX::TexCoordID tcid, GX::TexMapID tmid, GX::ChannelID cid) noexcept; void GXSetTevKColorSel(GX::TevStageID id, GX::TevKColorSel sel) noexcept; @@ -725,8 +724,7 @@ void GXSetChanAmbColor(GX::ChannelID id, const GXColor& color) noexcept; void GXSetChanMatColor(GX::ChannelID id, const GXColor& color) noexcept; void GXSetChanCtrl(GX::ChannelID id, GXBool lightingEnabled, GX::ColorSrc ambSrc, GX::ColorSrc matSrc, GX::LightMask lightState, GX::DiffuseFn diffFn, GX::AttnFn attnFn) noexcept; -// Originally u8 instead of floats -void GXSetAlphaCompare(GX::Compare comp0, float ref0, GX::AlphaOp op, GX::Compare comp1, float ref1) noexcept; +void GXSetAlphaCompare(GX::Compare comp0, u8 ref0, GX::AlphaOp op, GX::Compare comp1, u8 ref1) noexcept; void GXSetVtxDesc(GX::Attr attr, GX::AttrType type) noexcept; void GXSetVtxDescv(GX::VtxDescList* list) noexcept; void GXClearVtxDesc() noexcept; diff --git a/Runtime/Graphics/Shaders/CFluidPlaneShader.hpp b/Runtime/Graphics/Shaders/CFluidPlaneShader.hpp index 1702cb5d3..342f15861 100644 --- a/Runtime/Graphics/Shaders/CFluidPlaneShader.hpp +++ b/Runtime/Graphics/Shaders/CFluidPlaneShader.hpp @@ -87,17 +87,17 @@ private: zeus::CVector4f params; // amplitude, lookupPhase, lookupTime }; - struct Uniform { - zeus::CMatrix4f m_mv; - zeus::CMatrix4f m_mvNorm; - zeus::CMatrix4f m_proj; - std::array m_texMtxs; - std::array m_ripple; - zeus::CVector4f m_colorMul; - std::array m_pad; // rippleNormResolution, Pad out to 1280 bytes - CModelShaders::LightingUniform m_lighting; - zeus::CVector3f m_pad2; // Pad out to 768 bytes, also holds ind scale - }; +// struct Uniform { +// zeus::CMatrix4f m_mv; +// zeus::CMatrix4f m_mvNorm; +// zeus::CMatrix4f m_proj; +// std::array m_texMtxs; +// std::array m_ripple; +// zeus::CVector4f m_colorMul; +// std::array m_pad; // rippleNormResolution, Pad out to 1280 bytes +// CModelShaders::LightingUniform m_lighting; +// zeus::CVector3f m_pad2; // Pad out to 768 bytes, also holds ind scale +// }; TLockedToken m_patternTex1; TLockedToken m_patternTex2; diff --git a/Runtime/Graphics/Shaders/CModelShaders.cpp b/Runtime/Graphics/Shaders/CModelShaders.cpp index b1d44a829..192043249 100644 --- a/Runtime/Graphics/Shaders/CModelShaders.cpp +++ b/Runtime/Graphics/Shaders/CModelShaders.cpp @@ -10,54 +10,54 @@ namespace metaforce { //std::unordered_map CModelShaders::g_ShaderPipelines; -void CModelShaders::LightingUniform::ActivateLights(const std::vector& lts) { - ambient = zeus::skClear; - size_t curLight = 0; - - for (const CLight& light : lts) { - switch (light.GetType()) { - case ELightType::LocalAmbient: - ambient += light.GetColor(); - break; - case ELightType::Point: - case ELightType::Spot: - case ELightType::Custom: - case ELightType::Directional: { - if (curLight >= lights.size()) { - continue; - } - CModelShaders::Light& lightOut = lights[curLight++]; - lightOut.pos = CGraphics::g_CameraMatrix * light.GetPosition(); - lightOut.dir = CGraphics::g_CameraMatrix.basis * light.GetDirection(); - lightOut.dir.normalize(); - lightOut.color = light.GetColor(); - lightOut.linAtt[0] = light.GetAttenuationConstant(); - lightOut.linAtt[1] = light.GetAttenuationLinear(); - lightOut.linAtt[2] = light.GetAttenuationQuadratic(); - lightOut.angAtt[0] = light.GetAngleAttenuationConstant(); - lightOut.angAtt[1] = light.GetAngleAttenuationLinear(); - lightOut.angAtt[2] = light.GetAngleAttenuationQuadratic(); - - if (light.GetType() == ELightType::Directional) - lightOut.pos = (-lightOut.dir) * 1048576.f; - break; - } - } - } - - for (; curLight < lights.size(); ++curLight) { - CModelShaders::Light& lightOut = lights[curLight]; - lightOut.pos = zeus::skZero3f; - lightOut.dir = zeus::skDown; - lightOut.color = zeus::skClear; - lightOut.linAtt[0] = 1.f; - lightOut.linAtt[1] = 0.f; - lightOut.linAtt[2] = 0.f; - lightOut.angAtt[0] = 1.f; - lightOut.angAtt[1] = 0.f; - lightOut.angAtt[2] = 0.f; - } -} +//void CModelShaders::LightingUniform::ActivateLights(const std::vector& lts) { +// ambient = zeus::skClear; +// size_t curLight = 0; +// +// for (const CLight& light : lts) { +// switch (light.GetType()) { +// case ELightType::LocalAmbient: +// ambient += light.GetColor(); +// break; +// case ELightType::Point: +// case ELightType::Spot: +// case ELightType::Custom: +// case ELightType::Directional: { +// if (curLight >= lights.size()) { +// continue; +// } +// CModelShaders::Light& lightOut = lights[curLight++]; +// lightOut.pos = CGraphics::g_CameraMatrix * light.GetPosition(); +// lightOut.dir = CGraphics::g_CameraMatrix.basis * light.GetDirection(); +// lightOut.dir.normalize(); +// lightOut.color = light.GetColor(); +// lightOut.linAtt[0] = light.GetAttenuationConstant(); +// lightOut.linAtt[1] = light.GetAttenuationLinear(); +// lightOut.linAtt[2] = light.GetAttenuationQuadratic(); +// lightOut.angAtt[0] = light.GetAngleAttenuationConstant(); +// lightOut.angAtt[1] = light.GetAngleAttenuationLinear(); +// lightOut.angAtt[2] = light.GetAngleAttenuationQuadratic(); +// +// if (light.GetType() == ELightType::Directional) +// lightOut.pos = (-lightOut.dir) * 1048576.f; +// break; +// } +// } +// } +// +// for (; curLight < lights.size(); ++curLight) { +// CModelShaders::Light& lightOut = lights[curLight]; +// lightOut.pos = zeus::skZero3f; +// lightOut.dir = zeus::skDown; +// lightOut.color = zeus::skClear; +// lightOut.linAtt[0] = 1.f; +// lightOut.linAtt[1] = 0.f; +// lightOut.linAtt[2] = 0.f; +// lightOut.angAtt[0] = 1.f; +// lightOut.angAtt[1] = 0.f; +// lightOut.angAtt[2] = 0.f; +// } +//} //using TexCoordSource = hecl::Backend::TexCoordSource; // diff --git a/Runtime/Graphics/Shaders/CModelShaders.hpp b/Runtime/Graphics/Shaders/CModelShaders.hpp index a37e8c4c8..190edfe3d 100644 --- a/Runtime/Graphics/Shaders/CModelShaders.hpp +++ b/Runtime/Graphics/Shaders/CModelShaders.hpp @@ -59,43 +59,43 @@ class CModelShaders { friend class CModel; public: - struct Light { - zeus::CVector3f pos; - zeus::CVector3f dir; - zeus::CColor color = zeus::skClear; - std::array linAtt{1.f, 0.f, 0.f}; - std::array angAtt{1.f, 0.f, 0.f}; - }; - - struct LightingUniform { - std::array lights; - zeus::CColor ambient; - std::array colorRegs; - zeus::CColor mulColor; - zeus::CColor addColor; - CFogState fog; - - void ActivateLights(const std::vector& lts); - }; - - struct ThermalUniform { - zeus::CColor mulColor; - zeus::CColor addColor; - }; - - struct SolidUniform { - zeus::CColor solidColor; - }; - - struct MBShadowUniform { - zeus::CVector4f shadowUp; - float shadowId; - }; - - struct OneTextureUniform { - zeus::CColor addColor; - CFogState fog; - }; +// struct Light { +// zeus::CVector3f pos; +// zeus::CVector3f dir; +// zeus::CColor color = zeus::skClear; +// std::array linAtt{1.f, 0.f, 0.f}; +// std::array angAtt{1.f, 0.f, 0.f}; +// }; +// +// struct LightingUniform { +// std::array lights; +// zeus::CColor ambient; +// std::array colorRegs; +// zeus::CColor mulColor; +// zeus::CColor addColor; +// CFogState fog; +// +// void ActivateLights(const std::vector& lts); +// }; +// +// struct ThermalUniform { +// zeus::CColor mulColor; +// zeus::CColor addColor; +// }; +// +// struct SolidUniform { +// zeus::CColor solidColor; +// }; +// +// struct MBShadowUniform { +// zeus::CVector4f shadowUp; +// float shadowId; +// }; +// +// struct OneTextureUniform { +// zeus::CColor addColor; +// CFogState fog; +// }; static void Initialize(); static void Shutdown(); diff --git a/Runtime/MP1/CFrontEndUI.cpp b/Runtime/MP1/CFrontEndUI.cpp index a1ce3a8f4..ef721da2a 100644 --- a/Runtime/MP1/CFrontEndUI.cpp +++ b/Runtime/MP1/CFrontEndUI.cpp @@ -1841,9 +1841,7 @@ void CFrontEndUI::Draw() { /* To black */ zeus::CColor color = zeus::skBlack; color.a() = 1.f - x58_fadeBlackTimer; - zeus::CRectangle rect(0, 0, 1, 1); - aurora::gfx::queue_colored_quad(aurora::gfx::CameraFilterType::Blend, aurora::gfx::ZComp::Always, false, color, - rect, 0.f); + CCameraFilterPass::DrawFilter(EFilterType::Blend, EFilterShape::Fullscreen, color, nullptr, 1.f); } } @@ -1853,16 +1851,12 @@ void CFrontEndUI::Draw() { /* To black */ zeus::CColor color = zeus::skBlack; color.a() = zeus::clamp(0.f, 1.f - x58_fadeBlackTimer, 1.f); - zeus::CRectangle rect(0, 0, 1, 1); - aurora::gfx::queue_colored_quad(aurora::gfx::CameraFilterType::Blend, aurora::gfx::ZComp::Always, false, color, - rect, 0.f); + CCameraFilterPass::DrawFilter(EFilterType::Blend, EFilterShape::Fullscreen, color, nullptr, 1.f); } else if (x50_curScreen == EScreen::Title && x54_nextScreen == EScreen::Title) { /* From black with 30-sec skip to title */ zeus::CColor color = zeus::skBlack; color.a() = 1.f - zeus::clamp(0.f, 30.f - x58_fadeBlackTimer, 1.f); - zeus::CRectangle rect(0, 0, 1, 1); - aurora::gfx::queue_colored_quad(aurora::gfx::CameraFilterType::Blend, aurora::gfx::ZComp::Always, false, color, - rect, 0.f); + CCameraFilterPass::DrawFilter(EFilterType::Blend, EFilterShape::Fullscreen, color, nullptr, 1.f); } } diff --git a/aurora/CMakeLists.txt b/aurora/CMakeLists.txt index edee18b5a..2cd903268 100644 --- a/aurora/CMakeLists.txt +++ b/aurora/CMakeLists.txt @@ -11,8 +11,6 @@ add_library(aurora STATIC lib/gfx/gx_shader.cpp lib/gfx/texture_convert.cpp lib/gfx/movie_player/shader.cpp - lib/gfx/textured_quad/shader.cpp - lib/gfx/colored_quad/shader.cpp lib/gfx/stream/shader.cpp lib/gfx/model/shader.cpp ) diff --git a/aurora/include/aurora/gfx.hpp b/aurora/include/aurora/gfx.hpp index a49365af7..07143e997 100644 --- a/aurora/include/aurora/gfx.hpp +++ b/aurora/include/aurora/gfx.hpp @@ -18,22 +18,6 @@ #include namespace metaforce { -enum class ERglFogMode : uint32_t { - None = 0x00, - - PerspLin = 0x02, - PerspExp = 0x04, - PerspExp2 = 0x05, - PerspRevExp = 0x06, - PerspRevExp2 = 0x07, - - OrthoLin = 0x0A, - OrthoExp = 0x0C, - OrthoExp2 = 0x0D, - OrthoRevExp = 0x0E, - OrthoRevExp2 = 0x0F -}; - enum class ETexelFormat { Invalid = -1, I4 = 0, @@ -58,14 +42,6 @@ enum class EClampMode { Mirror, }; -struct CFogState { - zeus::CColor m_color; - float m_A = 0.f; - float m_B = 0.5f; - float m_C = 0.f; - ERglFogMode m_mode; -}; - enum class EStreamFlagBits : u8 { fHasNormal = 0x1, fHasColor = 0x2, @@ -83,15 +59,6 @@ struct TextureHandle { operator bool() const { return ref.operator bool(); } void reset() { ref.reset(); } }; -enum class TextureFormat : uint8_t { - RGBA8, - R8, - R32Float, - DXT1, - DXT3, - DXT5, - BPTC, -}; struct ClipRect { int32_t x; @@ -99,28 +66,6 @@ struct ClipRect { int32_t width; int32_t height; }; -enum class CameraFilterType : uint8_t { - Passthru, - Multiply, - Invert, - Add, - Subtract, - Blend, - Widescreen, - SceneAdd, - NoColor, - InvDstMultiply, -}; -enum class ZComp : uint8_t { - Never, - Less, - Equal, - LEqual, - Greater, - NEqual, - GEqual, - Always, -}; struct Light { zeus::CVector3f pos{0.f, 0.f, 0.f}; @@ -130,8 +75,6 @@ struct Light { zeus::CVector3f angAtt{1.f, 0.f, 0.f}; }; -[[nodiscard]] bool get_dxt_compression_supported() noexcept; - #ifndef NDEBUG #define AURORA_GFX_DEBUG_GROUPS #endif @@ -146,31 +89,16 @@ struct ScopedDebugGroup { void bind_texture(GX::TexMapID id, metaforce::EClampMode clamp, const TextureHandle& tex, float lod) noexcept; void unbind_texture(GX::TexMapID id) noexcept; -void update_fog_state(const metaforce::CFogState& state) noexcept; +// TODO migrate to GX void load_light(GX::LightID id, const Light& light) noexcept; void load_light_ambient(GX::LightID id, const zeus::CColor& ambient) noexcept; + void set_viewport(float left, float top, float width, float height, float znear, float zfar) noexcept; 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 add_material_set(/* TODO */) noexcept; -void add_model(/* TODO */) noexcept; - -void queue_aabb(const zeus::CAABox& aabb, const zeus::CColor& color, bool z_only) noexcept; -void queue_fog_volume_plane(const ArrayRef& verts, uint8_t pass); -void queue_fog_volume_filter(const zeus::CColor& color, bool two_way) noexcept; -void queue_textured_quad_verts(CameraFilterType filter_type, const TextureHandle& texture, ZComp z_comparison, - bool z_test, const zeus::CColor& color, const ArrayRef& pos, - const ArrayRef& uvs, float lod) noexcept; -void queue_textured_quad(CameraFilterType filter_type, const TextureHandle& texture, ZComp z_comparison, bool z_test, - const zeus::CColor& color, float uv_scale, const zeus::CRectangle& rect, float z, - float lod = 0) noexcept; -void queue_colored_quad_verts(CameraFilterType filter_type, ZComp z_comparison, bool z_test, const zeus::CColor& color, - const ArrayRef& pos) noexcept; -void queue_colored_quad(CameraFilterType filter_type, ZComp z_comparison, bool z_test, const zeus::CColor& color, - const zeus::CRectangle& rect, float z) noexcept; void queue_movie_player(const TextureHandle& tex_y, const TextureHandle& tex_u, const TextureHandle& tex_v, float h_pad, float v_pad) noexcept; diff --git a/aurora/lib/aurora.cpp b/aurora/lib/aurora.cpp index a638a2ffe..98ad5c344 100644 --- a/aurora/lib/aurora.cpp +++ b/aurora/lib/aurora.cpp @@ -242,7 +242,7 @@ void app_run(std::unique_ptr app, Icon icon, int argc, char** argv) SDL_DisableScreenSaver(); /* TODO: Make this an option rather than hard coding it */ - SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS,"1"); + SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1"); Uint32 flags = SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_RESIZABLE; switch (gpu::preferredBackendType) { @@ -421,9 +421,7 @@ void set_fullscreen(bool fullscreen) noexcept { SDL_SetWindowFullscreen(g_window, fullscreen ? SDL_WINDOW_FULLSCREEN : 0); } -uint32_t get_which_controller_for_player(int32_t index) noexcept { - return input::get_instance_for_player(index); -} +uint32_t get_which_controller_for_player(int32_t index) noexcept { return input::get_instance_for_player(index); } int32_t get_controller_player_index(uint32_t instance) noexcept { return input::player_index(instance); } void set_controller_player_index(uint32_t instance, int32_t index) noexcept { diff --git a/aurora/lib/gfx/colored_quad/shader.cpp b/aurora/lib/gfx/colored_quad/shader.cpp deleted file mode 100644 index 85ce3e67b..000000000 --- a/aurora/lib/gfx/colored_quad/shader.cpp +++ /dev/null @@ -1,310 +0,0 @@ -#include "shader.hpp" - -#include "../../gpu.hpp" -#include "../gx.hpp" - -#include -#include - -namespace aurora::gfx::colored_quad { -static logvisor::Module Log("aurora::gfx::colored_quad"); - -using gpu::g_device; -using gpu::g_graphicsConfig; -using gpu::utils::make_vertex_attributes; -using gpu::utils::make_vertex_buffer_layout; -using gpu::utils::make_vertex_state; - -State construct_state() { - wgpu::ShaderModuleWGSLDescriptor wgslDescriptor{}; - wgslDescriptor.source = R"""( -struct Uniform { - xf: mat4x4; - color: vec4; -}; -@group(0) @binding(0) -var ubuf: Uniform; - -struct VertexOutput { - @builtin(position) pos: vec4; - //@builtin(normal) norm: vec4; -}; - -@stage(vertex) -fn vs_main(@location(0) in_pos: vec3) -> VertexOutput {//, @location(1) in_norm: vec3) -> VertexOutput { - var out: VertexOutput; - out.pos = ubuf.xf * vec4(in_pos, 1.0); - //out.norm = in_norm; - return out; -} - -@stage(fragment) -fn fs_main(in: VertexOutput) -> @location(0) vec4 { - return ubuf.color; -} -)"""; - const auto shaderDescriptor = wgpu::ShaderModuleDescriptor{ - .nextInChain = &wgslDescriptor, - .label = "Colored Quad Shader", - }; - auto shader = g_device.CreateShaderModule(&shaderDescriptor); - - wgpu::SupportedLimits limits; - g_device.GetLimits(&limits); - const auto uniform_alignment = limits.limits.minUniformBufferOffsetAlignment; - const auto uniform_size = ALIGN(sizeof(Uniform), uniform_alignment); - - const std::array uniformLayoutEntries{ - wgpu::BindGroupLayoutEntry{ - .binding = 0, - .visibility = wgpu::ShaderStage::Vertex | wgpu::ShaderStage::Fragment, - .buffer = - wgpu::BufferBindingLayout{ - .type = wgpu::BufferBindingType::Uniform, - .hasDynamicOffset = true, - .minBindingSize = uniform_size, - }, - }, - }; - - const auto uniformLayoutDescriptor = wgpu::BindGroupLayoutDescriptor{ - .label = "Colored Quad Uniform Bind Group Layout", - .entryCount = uniformLayoutEntries.size(), - .entries = uniformLayoutEntries.data(), - }; - auto uniformLayout = g_device.CreateBindGroupLayout(&uniformLayoutDescriptor); - - const std::array uniformBindGroupEntries{ - wgpu::BindGroupEntry{ - .binding = 0, - .buffer = g_uniformBuffer, - .size = uniform_size, - }, - }; - - const auto uniformBindGroupDescriptor = wgpu::BindGroupDescriptor{ - .label = "Colored Quad Uniform Bind Group", - .layout = uniformLayout, - .entryCount = uniformBindGroupEntries.size(), - .entries = uniformBindGroupEntries.data(), - }; - auto uniformBindGroup = g_device.CreateBindGroup(&uniformBindGroupDescriptor); - - const std::array bindGroupLayouts{ - uniformLayout, - }; - - const auto pipelineLayoutDescriptor = wgpu::PipelineLayoutDescriptor{ - .label = "Colored Quad Pipeline Layout", - .bindGroupLayoutCount = bindGroupLayouts.size(), - .bindGroupLayouts = bindGroupLayouts.data(), - }; - auto pipelineLayout = g_device.CreatePipelineLayout(&pipelineLayoutDescriptor); - - return { - .shader = shader, - .uniformLayout = uniformLayout, - .uniformBindGroup = uniformBindGroup, - .pipelineLayout = pipelineLayout, - }; -} - -wgpu::RenderPipeline create_pipeline(const State& state, [[maybe_unused]] PipelineConfig config) { - const auto attributes = make_vertex_attributes(std::array{wgpu::VertexFormat::Float32x3}); - const std::array vertexBuffers{make_vertex_buffer_layout(sizeof(Vert), attributes)}; - - wgpu::CompareFunction depthCompare{}; - switch (config.zComparison) { - case ZComp::Never: - depthCompare = wgpu::CompareFunction::Never; - break; - case ZComp::Less: - depthCompare = wgpu::CompareFunction::Less; - break; - case ZComp::Equal: - depthCompare = wgpu::CompareFunction::Equal; - break; - case ZComp::LEqual: - depthCompare = wgpu::CompareFunction::LessEqual; - break; - case ZComp::Greater: - depthCompare = wgpu::CompareFunction::Greater; - break; - case ZComp::NEqual: - depthCompare = wgpu::CompareFunction::NotEqual; - break; - case ZComp::GEqual: - depthCompare = wgpu::CompareFunction::GreaterEqual; - break; - case ZComp::Always: - depthCompare = wgpu::CompareFunction::Always; - break; - } - const auto depthStencil = wgpu::DepthStencilState{ - .format = g_graphicsConfig.depthFormat, - .depthWriteEnabled = config.zTest, - .depthCompare = depthCompare, - }; - - bool alphaWrite = false; - wgpu::BlendComponent blendComponent{}; - switch (config.filterType) { - case CameraFilterType::Multiply: - blendComponent = wgpu::BlendComponent{ - .srcFactor = wgpu::BlendFactor::Zero, - .dstFactor = wgpu::BlendFactor::Src, - }; - alphaWrite = true; - break; - case CameraFilterType::Add: - blendComponent = wgpu::BlendComponent{ - .srcFactor = wgpu::BlendFactor::SrcAlpha, - .dstFactor = wgpu::BlendFactor::One, - }; - alphaWrite = false; - break; - case CameraFilterType::Subtract: - blendComponent = wgpu::BlendComponent{ - .operation = wgpu::BlendOperation::Subtract, - .srcFactor = wgpu::BlendFactor::SrcAlpha, - .dstFactor = wgpu::BlendFactor::One, - }; - alphaWrite = false; - break; - case CameraFilterType::Blend: - blendComponent = wgpu::BlendComponent{ - .srcFactor = wgpu::BlendFactor::SrcAlpha, - .dstFactor = wgpu::BlendFactor::OneMinusSrcAlpha, - }; - alphaWrite = false; - break; - case CameraFilterType::InvDstMultiply: - blendComponent = wgpu::BlendComponent{ - .srcFactor = wgpu::BlendFactor::Zero, - .dstFactor = wgpu::BlendFactor::OneMinusSrc, - }; - alphaWrite = true; - break; - default: - Log.report(logvisor::Fatal, FMT_STRING("unimplemented filter type {}"), magic_enum::enum_name(config.filterType)); - unreachable(); - } - - const auto blendState = wgpu::BlendState{ - .color = blendComponent, - .alpha = blendComponent, - }; - auto writeMask = wgpu::ColorWriteMask::Red | wgpu::ColorWriteMask::Green | wgpu::ColorWriteMask::Blue; - if (alphaWrite) { - writeMask = writeMask | wgpu::ColorWriteMask::Alpha; - } - const std::array colorTargets{ - wgpu::ColorTargetState{ - .format = g_graphicsConfig.colorFormat, - .blend = &blendState, - .writeMask = writeMask, - }, - }; - const auto fragmentState = wgpu::FragmentState{ - .module = state.shader, - .entryPoint = "fs_main", - .targetCount = colorTargets.size(), - .targets = colorTargets.data(), - }; - - const auto pipelineDescriptor = wgpu::RenderPipelineDescriptor{ - .label = "Colored Quad Pipeline", - .layout = state.pipelineLayout, - .vertex = make_vertex_state(state.shader, vertexBuffers), - .primitive = - wgpu::PrimitiveState{ - .topology = wgpu::PrimitiveTopology::TriangleStrip, - }, - .depthStencil = &depthStencil, - .multisample = - wgpu::MultisampleState{ - .count = g_graphicsConfig.msaaSamples, - }, - .fragment = &fragmentState, - }; - - return g_device.CreateRenderPipeline(&pipelineDescriptor); -} - -DrawData make_draw_data(const State& state, CameraFilterType filter_type, ZComp z_comparison, bool z_test, - const zeus::CColor& color, const zeus::CRectangle& rect, float z) { - auto pipeline = pipeline_ref(PipelineConfig{ - .filterType = filter_type, - .zComparison = z_comparison, - .zTest = z_test, - }); - - const std::array verts{ - Vert{{0.f, 0.f, z}}, - Vert{{0.f, 1.f, z}}, - Vert{{1.f, 0.f, z}}, - Vert{{1.f, 1.f, z}}, - }; - const auto vertRange = push_verts(ArrayRef{verts}); - - const auto uniform = Uniform{ - .xf = - Mat4x4{ - Vec4{rect.size.x() * 2.f, 0.f, 0.f, 0.f}, - Vec4{0.f, rect.size.y() * 2.f, 0.f, 0.f}, - Vec4{0.f, 0.f, 1.f, 0.f}, - Vec4{rect.position.x() * 2.f - 1.f, rect.position.y() * 2.f - 1.f, 0.f, 1.f}, - }, - .color = color, - }; - const auto uniformRange = push_uniform(uniform); - - return { - .pipeline = pipeline, - .vertRange = vertRange, - .uniformRange = uniformRange, - }; -} - -DrawData make_draw_data_verts(const State& state, CameraFilterType filter_type, ZComp z_comparison, bool z_test, - const zeus::CColor& color, const ArrayRef& pos) { - auto pipeline = pipeline_ref(PipelineConfig{ - .filterType = filter_type, - .zComparison = z_comparison, - .zTest = z_test, - }); - - assert(pos.size() == 4 && "Invalid pos size!"); - - const std::array verts{ - Vert{pos[0]}, - Vert{pos[1]}, - Vert{pos[2]}, - Vert{pos[3]}, - }; - const auto vertRange = push_verts(ArrayRef{verts}); - - const auto uniform = Uniform{ - .xf = gx::get_combined_matrix(), - .color = color, - }; - const auto uniformRange = push_uniform(uniform); - - return { - .pipeline = pipeline, - .vertRange = vertRange, - .uniformRange = uniformRange, - }; -} - -void render(const State& state, const DrawData& data, const wgpu::RenderPassEncoder& pass) { - if (!bind_pipeline(data.pipeline, pass)) { - return; - } - - const std::array offsets{data.uniformRange.offset}; - pass.SetBindGroup(0, state.uniformBindGroup, offsets.size(), offsets.data()); - pass.SetVertexBuffer(0, g_vertexBuffer, data.vertRange.offset, data.vertRange.size); - pass.Draw(4); -} -} // namespace aurora::gfx::colored_quad diff --git a/aurora/lib/gfx/colored_quad/shader.hpp b/aurora/lib/gfx/colored_quad/shader.hpp deleted file mode 100644 index 96091942c..000000000 --- a/aurora/lib/gfx/colored_quad/shader.hpp +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once - -#include "../common.hpp" - -namespace aurora::gfx::colored_quad { -struct DrawData { - PipelineRef pipeline; - Range vertRange; - Range uniformRange; -}; - -struct PipelineConfig { - CameraFilterType filterType; - ZComp zComparison; - bool zTest; -}; - -static const std::array INITIAL_PIPELINES { - PipelineConfig{}, // TODO -}; - -struct State { - wgpu::ShaderModule shader; - wgpu::BindGroupLayout uniformLayout; - wgpu::BindGroup uniformBindGroup; - wgpu::Sampler sampler; - wgpu::PipelineLayout pipelineLayout; -}; - -struct alignas(4) Vert { - Vec3 pos; -}; - -struct alignas(4) Uniform { - Mat4x4 xf; - Vec4 color; -}; -static_assert(sizeof(Uniform) == 80); - -State construct_state(); -wgpu::RenderPipeline create_pipeline(const State& state, [[maybe_unused]] PipelineConfig config); -DrawData make_draw_data(const State& state, CameraFilterType filter_type, ZComp z_comparison, bool z_test, - const zeus::CColor& color, const zeus::CRectangle& rect, float z); - -DrawData make_draw_data_verts(const State& state, CameraFilterType filter_type, ZComp z_comparison, bool z_test, - const zeus::CColor& color, const ArrayRef& pos); - -void render(const State& state, const DrawData& data, const wgpu::RenderPassEncoder& pass); -} // namespace aurora::gfx::colored_quad diff --git a/aurora/lib/gfx/common.cpp b/aurora/lib/gfx/common.cpp index 939719f4c..528af39dd 100644 --- a/aurora/lib/gfx/common.cpp +++ b/aurora/lib/gfx/common.cpp @@ -1,17 +1,15 @@ #include "common.hpp" #include "../gpu.hpp" -#include "colored_quad/shader.hpp" +#include "model/shader.hpp" #include "movie_player/shader.hpp" #include "stream/shader.hpp" -#include "textured_quad/shader.hpp" -#include "model/shader.hpp" +#include #include #include #include #include -#include namespace aurora::gfx { static logvisor::Module Log("aurora::gfx"); @@ -32,8 +30,6 @@ constexpr uint64_t StagingBufferSize = UniformBufferSize + VertexBufferSize + In struct ShaderState { movie_player::State moviePlayer; - colored_quad::State coloredQuad; - textured_quad::State texturedQuad; stream::State stream; model::State model; }; @@ -41,22 +37,10 @@ struct ShaderDrawCommand { ShaderType type; union { movie_player::DrawData moviePlayer; - colored_quad::DrawData coloredQuad; - textured_quad::DrawData texturedQuad; stream::DrawData stream; model::DrawData model; }; }; -struct PipelineCreateCommand { - ShaderType type; - union { - movie_player::PipelineConfig moviePlayer; - colored_quad::PipelineConfig coloredQuad; - textured_quad::PipelineConfig texturedQuad; - stream::PipelineConfig stream; - model::PipelineConfig model; - }; -}; enum class CommandType { SetViewport, SetScissor, @@ -90,108 +74,21 @@ struct Command { } // namespace aurora::gfx namespace aurora { +// For types that we can't ensure are safe to hash with has_unique_object_representations, +// we create specialized methods to handle them. Note that these are highly dependent on +// the structure definition, which could easily change with Dawn updates. template <> -inline void xxh3_update(XXH3_state_t& state, const gfx::colored_quad::PipelineConfig& input) { - XXH3_64bits_update(&state, &input.filterType, sizeof(gfx::colored_quad::PipelineConfig::filterType)); - XXH3_64bits_update(&state, &input.zComparison, sizeof(gfx::colored_quad::PipelineConfig::zComparison)); - XXH3_64bits_update(&state, &input.zTest, sizeof(gfx::colored_quad::PipelineConfig::zTest)); +inline XXH64_hash_t xxh3_hash(const wgpu::BindGroupDescriptor& input, XXH64_hash_t seed) { + constexpr auto offset = sizeof(void*) * 2; // skip nextInChain, label + const auto hash = xxh3_hash_s(reinterpret_cast(&input) + offset, + sizeof(wgpu::BindGroupDescriptor) - offset - sizeof(void*) /* skip entries */, seed); + return xxh3_hash_s(input.entries, sizeof(wgpu::BindGroupEntry) * input.entryCount, hash); } template <> -inline void xxh3_update(XXH3_state_t& state, const gfx::textured_quad::PipelineConfig& input) { - XXH3_64bits_update(&state, &input.filterType, sizeof(gfx::textured_quad::PipelineConfig::filterType)); - XXH3_64bits_update(&state, &input.zComparison, sizeof(gfx::textured_quad::PipelineConfig::zComparison)); - XXH3_64bits_update(&state, &input.zTest, sizeof(gfx::textured_quad::PipelineConfig::zTest)); -} -template <> -inline void xxh3_update(XXH3_state_t& state, const gfx::movie_player::PipelineConfig& input) { - // no-op -} -template <> -inline void xxh3_update(XXH3_state_t& state, const gfx::gx::PipelineConfig& input) { - xxh3_update(state, input.shaderConfig); - XXH3_64bits_update(&state, &input.primitive, sizeof(gfx::gx::PipelineConfig::primitive)); - XXH3_64bits_update(&state, &input.depthFunc, sizeof(gfx::gx::PipelineConfig::depthFunc)); - XXH3_64bits_update(&state, &input.cullMode, sizeof(gfx::gx::PipelineConfig::cullMode)); - XXH3_64bits_update(&state, &input.blendMode, sizeof(gfx::gx::PipelineConfig::blendMode)); - XXH3_64bits_update(&state, &input.blendFacSrc, sizeof(gfx::gx::PipelineConfig::blendFacSrc)); - XXH3_64bits_update(&state, &input.blendFacDst, sizeof(gfx::gx::PipelineConfig::blendFacDst)); - XXH3_64bits_update(&state, &input.blendOp, sizeof(gfx::gx::PipelineConfig::blendOp)); - if (input.dstAlpha) { - XXH3_64bits_update(&state, &*input.dstAlpha, sizeof(float)); - } - XXH3_64bits_update(&state, &input.depthCompare, sizeof(gfx::gx::PipelineConfig::depthCompare)); - XXH3_64bits_update(&state, &input.depthUpdate, sizeof(gfx::gx::PipelineConfig::depthUpdate)); - XXH3_64bits_update(&state, &input.alphaUpdate, sizeof(gfx::gx::PipelineConfig::alphaUpdate)); -} -template <> -inline void xxh3_update(XXH3_state_t& state, const gfx::stream::PipelineConfig& input) { - xxh3_update(state, input); -} -template <> -inline void xxh3_update(XXH3_state_t& state, const gfx::model::PipelineConfig& input) { - xxh3_update(state, input); -} -template <> -inline void xxh3_update(XXH3_state_t& state, const gfx::PipelineCreateCommand& input) { - XXH3_64bits_update(&state, &input.type, sizeof(gfx::PipelineCreateCommand::type)); - switch (input.type) { - case gfx::ShaderType::Aabb: - // TODO - break; - case gfx::ShaderType::ColoredQuad: - xxh3_update(state, input.coloredQuad); - break; - case gfx::ShaderType::TexturedQuad: - xxh3_update(state, input.texturedQuad); - break; - case gfx::ShaderType::MoviePlayer: - xxh3_update(state, input.moviePlayer); - break; - case gfx::ShaderType::Stream: - xxh3_update(state, input.stream); - break; - case gfx::ShaderType::Model: - xxh3_update(state, input.model); - break; - } -} -template <> -inline void xxh3_update(XXH3_state_t& state, const wgpu::BindGroupEntry& input) { - XXH3_64bits_update(&state, &input.binding, sizeof(wgpu::BindGroupEntry::binding)); - XXH3_64bits_update(&state, &input.buffer, sizeof(wgpu::BindGroupEntry::buffer)); - XXH3_64bits_update(&state, &input.offset, sizeof(wgpu::BindGroupEntry::offset)); - if (input.buffer != nullptr) { - XXH3_64bits_update(&state, &input.size, sizeof(wgpu::BindGroupEntry::size)); - } - XXH3_64bits_update(&state, &input.sampler, sizeof(wgpu::BindGroupEntry::sampler)); - XXH3_64bits_update(&state, &input.textureView, sizeof(wgpu::BindGroupEntry::textureView)); -} -template <> -inline void xxh3_update(XXH3_state_t& state, const wgpu::BindGroupDescriptor& input) { - if (input.label != nullptr) { - XXH3_64bits_update(&state, input.label, strlen(input.label)); - } - XXH3_64bits_update(&state, &input.layout, sizeof(wgpu::BindGroupDescriptor::layout)); - XXH3_64bits_update(&state, &input.entryCount, sizeof(wgpu::BindGroupDescriptor::entryCount)); - for (int i = 0; i < input.entryCount; ++i) { - xxh3_update(state, input.entries[i]); - } -} -template <> -inline void xxh3_update(XXH3_state_t& state, const wgpu::SamplerDescriptor& input) { - if (input.label != nullptr) { - XXH3_64bits_update(&state, input.label, strlen(input.label)); - } - XXH3_64bits_update(&state, &input.addressModeU, sizeof(wgpu::SamplerDescriptor::addressModeU)); - XXH3_64bits_update(&state, &input.addressModeV, sizeof(wgpu::SamplerDescriptor::addressModeV)); - XXH3_64bits_update(&state, &input.addressModeW, sizeof(wgpu::SamplerDescriptor::addressModeW)); - XXH3_64bits_update(&state, &input.magFilter, sizeof(wgpu::SamplerDescriptor::magFilter)); - XXH3_64bits_update(&state, &input.minFilter, sizeof(wgpu::SamplerDescriptor::minFilter)); - XXH3_64bits_update(&state, &input.mipmapFilter, sizeof(wgpu::SamplerDescriptor::mipmapFilter)); - XXH3_64bits_update(&state, &input.lodMinClamp, sizeof(wgpu::SamplerDescriptor::lodMinClamp)); - XXH3_64bits_update(&state, &input.lodMaxClamp, sizeof(wgpu::SamplerDescriptor::lodMaxClamp)); - XXH3_64bits_update(&state, &input.compare, sizeof(wgpu::SamplerDescriptor::compare)); - XXH3_64bits_update(&state, &input.maxAnisotropy, sizeof(wgpu::SamplerDescriptor::maxAnisotropy)); +inline XXH64_hash_t xxh3_hash(const wgpu::SamplerDescriptor& input, XXH64_hash_t seed) { + constexpr auto offset = sizeof(void*) * 2; // skip nextInChain, label + return xxh3_hash_s(reinterpret_cast(&input) + offset, + sizeof(wgpu::SamplerDescriptor) - offset - 2 /* skip padding */, seed); } } // namespace aurora @@ -220,14 +117,14 @@ wgpu::Buffer g_indexBuffer; wgpu::Buffer g_storageBuffer; size_t g_staticStorageLastSize = 0; static std::array g_stagingBuffers; +static wgpu::SupportedLimits g_cachedLimits; static ShaderState g_state; static PipelineRef g_currentPipeline; static std::vector g_commands; -static PipelineRef find_pipeline(PipelineCreateCommand command, NewPipelineCallback&& cb) { - const auto hash = xxh3_hash(command); +static void find_pipeline(PipelineRef hash, NewPipelineCallback&& cb) { bool found = false; { std::scoped_lock guard{g_pipelineMutex}; @@ -252,7 +149,6 @@ static PipelineRef find_pipeline(PipelineCreateCommand command, NewPipelineCallb g_pipelineCv.notify_one(); queuedPipelines++; } - return hash; } static void push_draw_command(ShaderDrawCommand data) { @@ -265,8 +161,6 @@ static void push_draw_command(ShaderDrawCommand data) { }); } -bool get_dxt_compression_supported() noexcept { return g_device.HasFeature(wgpu::FeatureName::TextureCompressionBC); } - 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}; @@ -303,57 +197,6 @@ void resolve_depth(const ClipRect& rect, uint32_t bind) noexcept { // TODO } -void add_material_set(/* TODO */) noexcept {} -void add_model(/* TODO */) noexcept {} - -void queue_aabb(const zeus::CAABox& aabb, const zeus::CColor& color, bool z_only) noexcept { - // TODO -} - -void queue_fog_volume_plane(const ArrayRef& verts, uint8_t pass) { - // TODO -} - -void queue_fog_volume_filter(const zeus::CColor& color, bool two_way) noexcept { - // TODO -} - -void queue_textured_quad_verts(CameraFilterType filter_type, const TextureHandle& texture, ZComp z_comparison, - bool z_test, const zeus::CColor& color, const ArrayRef& pos, - const ArrayRef& uvs, float lod) noexcept { - auto data = textured_quad::make_draw_data_verts(g_state.texturedQuad, filter_type, texture, z_comparison, z_test, - color, pos, uvs, lod); - push_draw_command({.type = ShaderType::TexturedQuad, .texturedQuad = data}); -} -void queue_textured_quad(CameraFilterType filter_type, const TextureHandle& texture, ZComp z_comparison, bool z_test, - const zeus::CColor& color, float uv_scale, const zeus::CRectangle& rect, float z, - float lod) noexcept { - auto data = textured_quad::make_draw_data(g_state.texturedQuad, filter_type, texture, z_comparison, z_test, color, - uv_scale, rect, z, lod); - push_draw_command({.type = ShaderType::TexturedQuad, .texturedQuad = data}); -} -template <> -PipelineRef pipeline_ref(textured_quad::PipelineConfig config) { - return find_pipeline({.type = ShaderType::TexturedQuad, .texturedQuad = config}, - [=]() { return create_pipeline(g_state.texturedQuad, config); }); -} - -void queue_colored_quad_verts(CameraFilterType filter_type, ZComp z_comparison, bool z_test, const zeus::CColor& color, - const ArrayRef& pos) noexcept { - auto data = colored_quad::make_draw_data_verts(g_state.coloredQuad, filter_type, z_comparison, z_test, color, pos); - push_draw_command({.type = ShaderType::ColoredQuad, .coloredQuad = data}); -} -void queue_colored_quad(CameraFilterType filter_type, ZComp z_comparison, bool z_test, const zeus::CColor& color, - const zeus::CRectangle& rect, float z) noexcept { - auto data = colored_quad::make_draw_data(g_state.coloredQuad, filter_type, z_comparison, z_test, color, rect, z); - push_draw_command({.type = ShaderType::ColoredQuad, .coloredQuad = data}); -} -template <> -PipelineRef pipeline_ref(colored_quad::PipelineConfig config) { - return find_pipeline({.type = ShaderType::ColoredQuad, .coloredQuad = config}, - [=]() { return create_pipeline(g_state.coloredQuad, config); }); -} - 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); @@ -361,8 +204,9 @@ void queue_movie_player(const TextureHandle& tex_y, const TextureHandle& tex_u, } template <> PipelineRef pipeline_ref(movie_player::PipelineConfig config) { - return find_pipeline({.type = ShaderType::MoviePlayer, .moviePlayer = config}, - [=]() { return create_pipeline(g_state.moviePlayer, config); }); + PipelineRef ref = xxh3_hash(config, static_cast(ShaderType::MoviePlayer)); + find_pipeline(ref, [=]() { return create_pipeline(g_state.moviePlayer, config); }); + return ref; } template <> @@ -375,8 +219,9 @@ void push_draw_command(stream::DrawData data) { } template <> PipelineRef pipeline_ref(stream::PipelineConfig config) { - return find_pipeline({.type = ShaderType::Stream, .stream = config}, - [=]() { return create_pipeline(g_state.stream, config); }); + PipelineRef ref = xxh3_hash(config, static_cast(ShaderType::Stream)); + find_pipeline(ref, [=]() { return create_pipeline(g_state.stream, config); }); + return ref; } template <> @@ -385,8 +230,9 @@ void push_draw_command(model::DrawData data) { } template <> PipelineRef pipeline_ref(model::PipelineConfig config) { - return find_pipeline({.type = ShaderType::Model, .model = config}, - [=]() { return create_pipeline(g_state.model, config); }); + PipelineRef ref = xxh3_hash(config, static_cast(ShaderType::Model)); + find_pipeline(ref, [=]() { return create_pipeline(g_state.model, config); }); + return ref; } static void pipeline_worker() { @@ -426,6 +272,9 @@ void initialize() { g_hasPipelineThread = true; } + // For uniform & storage buffer offset alignments + g_device.GetLimits(&g_cachedLimits); + const auto createBuffer = [](wgpu::Buffer& out, wgpu::BufferUsage usage, uint64_t size, const char* label) { const wgpu::BufferDescriptor descriptor{ .label = label, @@ -443,14 +292,13 @@ void initialize() { createBuffer(g_storageBuffer, wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopyDst, StorageBufferSize, "Shared Storage Buffer"); for (int i = 0; i < g_stagingBuffers.size(); ++i) { + const auto label = fmt::format(FMT_STRING("Staging Buffer {}"), i); createBuffer(g_stagingBuffers[i], wgpu::BufferUsage::MapWrite | wgpu::BufferUsage::CopySrc, StagingBufferSize, - "Staging Buffer"); + label.c_str()); } map_staging_buffer(); g_state.moviePlayer = movie_player::construct_state(); - g_state.coloredQuad = colored_quad::construct_state(); - g_state.texturedQuad = textured_quad::construct_state(); g_state.stream = stream::construct_state(); g_state.model = model::construct_state(); } @@ -566,15 +414,6 @@ void render(const wgpu::RenderPassEncoder& pass) { case CommandType::Draw: { const auto& draw = cmd.data.draw; switch (draw.type) { - case ShaderType::Aabb: - // TODO - break; - case ShaderType::ColoredQuad: - colored_quad::render(g_state.coloredQuad, draw.coloredQuad, pass); - break; - case ShaderType::TexturedQuad: - textured_quad::render(g_state.texturedQuad, draw.texturedQuad, pass); - break; case ShaderType::MoviePlayer: movie_player::render(g_state.moviePlayer, draw.moviePlayer, pass); break; @@ -644,19 +483,13 @@ static inline Range map(ByteBuffer& target, size_t length, size_t alignment) { Range push_verts(const uint8_t* data, size_t length) { return push(g_verts, data, length, 4); } Range push_indices(const uint8_t* data, size_t length) { return push(g_indices, data, length, 4); } Range push_uniform(const uint8_t* data, size_t length) { - wgpu::SupportedLimits limits; - g_device.GetLimits(&limits); - return push(g_uniforms, data, length, limits.limits.minUniformBufferOffsetAlignment); + return push(g_uniforms, data, length, g_cachedLimits.limits.minUniformBufferOffsetAlignment); } Range push_storage(const uint8_t* data, size_t length) { - wgpu::SupportedLimits limits; - g_device.GetLimits(&limits); - return push(g_storage, data, length, limits.limits.minStorageBufferOffsetAlignment); + return push(g_storage, data, length, g_cachedLimits.limits.minStorageBufferOffsetAlignment); } Range push_static_storage(const uint8_t* data, size_t length) { - wgpu::SupportedLimits limits; - g_device.GetLimits(&limits); - auto range = push(g_staticStorage, data, length, limits.limits.minStorageBufferOffsetAlignment); + auto range = push(g_staticStorage, data, length, g_cachedLimits.limits.minStorageBufferOffsetAlignment); range.isStatic = true; return range; } @@ -669,15 +502,11 @@ std::pair map_indices(size_t length) { return {ByteBuffer{g_indices.data() + range.offset, range.size}, range}; } std::pair map_uniform(size_t length) { - wgpu::SupportedLimits limits; - g_device.GetLimits(&limits); - const auto range = map(g_uniforms, length, limits.limits.minUniformBufferOffsetAlignment); + const auto range = map(g_uniforms, length, g_cachedLimits.limits.minUniformBufferOffsetAlignment); return {ByteBuffer{g_uniforms.data() + range.offset, range.size}, range}; } std::pair map_storage(size_t length) { - wgpu::SupportedLimits limits; - g_device.GetLimits(&limits); - const auto range = map(g_storage, length, limits.limits.minStorageBufferOffsetAlignment); + const auto range = map(g_storage, length, g_cachedLimits.limits.minStorageBufferOffsetAlignment); return {ByteBuffer{g_storage.data() + range.offset, range.size}, range}; } @@ -707,9 +536,7 @@ const wgpu::Sampler& sampler_ref(const wgpu::SamplerDescriptor& descriptor) { } uint32_t align_uniform(uint32_t value) { - wgpu::SupportedLimits limits; - g_device.GetLimits(&limits); // TODO cache - const auto uniform_alignment = limits.limits.minUniformBufferOffsetAlignment; + const auto uniform_alignment = g_cachedLimits.limits.minUniformBufferOffsetAlignment; return ALIGN(value, uniform_alignment); } diff --git a/aurora/lib/gfx/common.hpp b/aurora/lib/gfx/common.hpp index e990ed0d2..6fed9810c 100644 --- a/aurora/lib/gfx/common.hpp +++ b/aurora/lib/gfx/common.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -11,18 +12,15 @@ #endif namespace aurora { -template -static inline void xxh3_update(XXH3_state_t& state, const T& input); -static inline XXH64_hash_t xxh3_hash(const void* input, size_t len, XXH64_hash_t seed = 0) { +static inline XXH64_hash_t xxh3_hash_s(const void* input, size_t len, XXH64_hash_t seed = 0) { return XXH3_64bits_withSeed(input, len, seed); } template static inline XXH64_hash_t xxh3_hash(const T& input, XXH64_hash_t seed = 0) { - XXH3_state_t state; - memset(&state, 0, sizeof(XXH3_state_t)); - XXH3_64bits_reset_withSeed(&state, seed); - xxh3_update(state, input); - return XXH3_64bits_digest(&state); + // Validate that the type has no padding bytes, which can easily cause + // hash mismatches. This also disallows floats, but that's okay for us. + static_assert(std::has_unique_object_representations_v); + return xxh3_hash_s(&input, sizeof(T), seed); } class ByteBuffer { @@ -160,9 +158,6 @@ static inline uint32_t storage_offset(Range range) { } enum class ShaderType { - Aabb, - ColoredQuad, - TexturedQuad, MoviePlayer, Stream, Model, diff --git a/aurora/lib/gfx/gx.cpp b/aurora/lib/gfx/gx.cpp index c639ac935..0bf56c823 100644 --- a/aurora/lib/gfx/gx.cpp +++ b/aurora/lib/gfx/gx.cpp @@ -56,11 +56,11 @@ void GXSetTevKColor(GX::TevKColorID id, const zeus::CColor& color) noexcept { g_gxState.kcolors[id] = color; } void GXSetAlphaUpdate(bool enabled) noexcept { g_gxState.alphaUpdate = enabled; } -void GXSetDstAlpha(bool enabled, float value) noexcept { +void GXSetDstAlpha(bool enabled, u8 value) noexcept { if (enabled) { g_gxState.dstAlpha = value; } else { - g_gxState.dstAlpha.reset(); + g_gxState.dstAlpha = UINT32_MAX; } } void GXSetCopyClear(const zeus::CColor& color, float depth) noexcept { g_gxState.clearColor = color; } @@ -107,7 +107,7 @@ void GXSetChanCtrl(GX::ChannelID id, bool lightingEnabled, GX::ColorSrc ambSrc, chan.matSrc = matSrc; g_gxState.colorChannelState[idx].lightState = lightState; } -void GXSetAlphaCompare(GX::Compare comp0, float ref0, GX::AlphaOp op, GX::Compare comp1, float ref1) noexcept { +void GXSetAlphaCompare(GX::Compare comp0, u8 ref0, GX::AlphaOp op, GX::Compare comp1, u8 ref1) noexcept { g_gxState.alphaCompare = {comp0, ref0, op, comp1, ref1}; } void GXSetTexCoordGen2(GX::TexCoordID dst, GX::TexGenType type, GX::TexGenSrc src, GX::TexMtx mtx, GXBool normalize, @@ -203,6 +203,9 @@ void GXSetTevSwapMode(GX::TevStageID stageId, GX::TevSwapSel rasSel, GX::TevSwap stage.tevSwapRas = rasSel; stage.tevSwapTex = texSel; } +void GXSetLineWidth(u8 width, GX::TexOffset offs) noexcept { + // TODO +} namespace aurora::gfx { static logvisor::Module Log("aurora::gfx::gx"); @@ -282,7 +285,7 @@ static inline wgpu::CompareFunction to_compare_function(GX::Compare func) { } static inline wgpu::BlendState to_blend_state(GX::BlendMode mode, GX::BlendFactor srcFac, GX::BlendFactor dstFac, - GX::LogicOp op, std::optional dstAlpha) { + GX::LogicOp op, u32 dstAlpha) { wgpu::BlendComponent colorBlendComponent; switch (mode) { case GX::BM_NONE: @@ -364,7 +367,7 @@ static inline wgpu::BlendState to_blend_state(GX::BlendMode mode, GX::BlendFacto .srcFactor = wgpu::BlendFactor::SrcAlpha, .dstFactor = wgpu::BlendFactor::Zero, }; - if (dstAlpha) { + if (dstAlpha != UINT32_MAX) { alphaBlendComponent = wgpu::BlendComponent{ .operation = wgpu::BlendOperation::Add, .srcFactor = wgpu::BlendFactor::Constant, @@ -474,14 +477,14 @@ wgpu::RenderPipeline build_pipeline(const PipelineConfig& config, const ShaderIn return g_device.CreateRenderPipeline(&descriptor); } -ShaderInfo populate_pipeline_config(PipelineConfig& config, GX::Primitive primitive, - const BindGroupRanges& ranges) noexcept { +void populate_pipeline_config(PipelineConfig& config, GX::Primitive primitive) noexcept { config.shaderConfig.fogType = g_gxState.fog.type; config.shaderConfig.vtxAttrs = g_gxState.vtxDesc; config.shaderConfig.tevSwapTable = g_gxState.tevSwapTable; for (u8 i = 0; i < g_gxState.numTevStages; ++i) { config.shaderConfig.tevStages[i] = g_gxState.tevStages[i]; } + config.shaderConfig.tevStageCount = g_gxState.numTevStages; for (u8 i = 0; i < g_gxState.numChans; ++i) { config.shaderConfig.colorChannels[i] = g_gxState.colorChannelConfig[i]; } @@ -506,13 +509,6 @@ ShaderInfo populate_pipeline_config(PipelineConfig& config, GX::Primitive primit .depthUpdate = g_gxState.depthUpdate, .alphaUpdate = g_gxState.alphaUpdate, }; - // TODO separate shader info from build_shader for async - { - std::lock_guard lk{g_pipelineMutex}; - auto [_, info] = build_shader(config.shaderConfig); - info.bindGroups = build_bind_groups(info, config.shaderConfig, ranges); // TODO this is hack - return info; - } } Range build_uniform(const ShaderInfo& info) noexcept { diff --git a/aurora/lib/gfx/gx.hpp b/aurora/lib/gfx/gx.hpp index 862233525..f052b68bd 100644 --- a/aurora/lib/gfx/gx.hpp +++ b/aurora/lib/gfx/gx.hpp @@ -2,6 +2,7 @@ #include "common.hpp" +#include #include namespace aurora::gfx::gx { @@ -24,14 +25,18 @@ struct TevPass { Arg d = Default; bool operator==(const TevPass&) const = default; }; +static_assert(std::has_unique_object_representations_v>); +static_assert(std::has_unique_object_representations_v>); struct TevOp { GX::TevOp op = GX::TevOp::TEV_ADD; GX::TevBias bias = GX::TevBias::TB_ZERO; GX::TevScale scale = GX::TevScale::CS_SCALE_1; GX::TevRegID outReg = GX::TevRegID::TEVPREV; bool clamp = true; + u32 _pad : 24 = 0; bool operator==(const TevOp&) const = default; }; +static_assert(std::has_unique_object_representations_v); struct TevStage { TevPass colorPass; TevPass alphaPass; @@ -46,6 +51,7 @@ struct TevStage { GX::TevSwapSel tevSwapTex = GX::TEV_SWAP0; bool operator==(const TevStage&) const = default; }; +static_assert(std::has_unique_object_representations_v); struct TextureBind { aurora::gfx::TextureHandle handle; metaforce::EClampMode clampMode; @@ -63,8 +69,10 @@ struct ColorChannelConfig { GX::ColorSrc matSrc = GX::SRC_REG; GX::ColorSrc ambSrc = GX::SRC_REG; bool lightingEnabled = false; + u32 _pad : 24 = 0; bool operator==(const ColorChannelConfig&) const = default; }; +static_assert(std::has_unique_object_representations_v); // For uniform generation struct ColorChannelState { zeus::CColor matColor; @@ -80,8 +88,10 @@ struct TcgConfig { GX::TexMtx mtx = GX::IDENTITY; GX::PTTexMtx postMtx = GX::PTIDENTITY; bool normalize = false; + u32 _pad : 24 = 0; bool operator==(const TcgConfig&) const = default; }; +static_assert(std::has_unique_object_representations_v); struct FogState { GX::FogType type = GX::FOG_NONE; float startZ = 0.f; @@ -98,15 +108,17 @@ struct TevSwap { bool operator==(const TevSwap&) const = default; operator bool() const { return *this != TevSwap{}; } }; +static_assert(std::has_unique_object_representations_v); struct AlphaCompare { GX::Compare comp0 = GX::ALWAYS; - float ref0 = 0.f; + u32 ref0; // would be u8 but extended to avoid padding bytes GX::AlphaOp op = GX::AOP_AND; GX::Compare comp1 = GX::ALWAYS; - float ref1 = 0.f; + u32 ref1; bool operator==(const AlphaCompare& other) const = default; operator bool() const { return *this != AlphaCompare{}; } }; +static_assert(std::has_unique_object_representations_v); struct GXState { zeus::CMatrix4f mv; @@ -120,7 +132,7 @@ struct GXState { GX::LogicOp blendOp = GX::LO_CLEAR; GX::Compare depthFunc = GX::LEQUAL; zeus::CColor clearColor = zeus::skBlack; - std::optional dstAlpha; + u32 dstAlpha; // u8; UINT32_MAX = disabled AlphaCompare alphaCompare; std::array colorRegs; std::array kcolors; @@ -158,13 +170,15 @@ struct ShaderConfig { GX::FogType fogType; std::array vtxAttrs; std::array tevSwapTable; - std::array, MaxTevStages> tevStages; + std::array tevStages; + u32 tevStageCount = 0; std::array colorChannels; std::array tcgs; AlphaCompare alphaCompare; u32 indexedAttributeCount = 0; bool operator==(const ShaderConfig&) const = default; }; +static_assert(std::has_unique_object_representations_v); struct PipelineConfig { ShaderConfig shaderConfig; GX::Primitive primitive; @@ -173,9 +187,11 @@ struct PipelineConfig { GX::BlendMode blendMode; GX::BlendFactor blendFacSrc, blendFacDst; GX::LogicOp blendOp; - std::optional dstAlpha; + u32 dstAlpha; bool depthCompare, depthUpdate, alphaUpdate; + u8 _pad; }; +static_assert(std::has_unique_object_representations_v); struct GXBindGroupLayouts { wgpu::BindGroupLayout uniformLayout; wgpu::BindGroupLayout samplerLayout; @@ -188,7 +204,6 @@ struct GXBindGroups { }; // Output info from shader generation struct ShaderInfo { - GXBindGroups bindGroups; std::bitset sampledTextures; std::bitset sampledKColors; std::bitset sampledColorChannels; @@ -205,92 +220,15 @@ struct BindGroupRanges { Range tcDataRange; Range packedTcDataRange; }; -ShaderInfo populate_pipeline_config(PipelineConfig& config, GX::Primitive primitive, - const BindGroupRanges& ranges) noexcept; +void populate_pipeline_config(PipelineConfig& config, GX::Primitive primitive) noexcept; wgpu::RenderPipeline build_pipeline(const PipelineConfig& config, const ShaderInfo& info, ArrayRef vtxBuffers, wgpu::ShaderModule shader, zstring_view label) noexcept; -std::pair build_shader(const ShaderConfig& config) noexcept; +ShaderInfo build_shader_info(const ShaderConfig& config) noexcept; +wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& info) noexcept; // Range build_vertex_buffer(const GXShaderInfo& info) noexcept; Range build_uniform(const ShaderInfo& info) noexcept; GXBindGroupLayouts build_bind_group_layouts(const ShaderInfo& info, const ShaderConfig& config) noexcept; GXBindGroups build_bind_groups(const ShaderInfo& info, const ShaderConfig& config, const BindGroupRanges& ranges) noexcept; } // namespace aurora::gfx::gx - -namespace aurora { -template -inline void xxh3_update(XXH3_state_t& state, const gfx::gx::TevPass& input) { - XXH3_64bits_update(&state, &input.a, sizeof(Arg)); - XXH3_64bits_update(&state, &input.b, sizeof(Arg)); - XXH3_64bits_update(&state, &input.c, sizeof(Arg)); - XXH3_64bits_update(&state, &input.d, sizeof(Arg)); -} -template <> -inline void xxh3_update(XXH3_state_t& state, const gfx::gx::TevOp& input) { - XXH3_64bits_update(&state, &input.op, sizeof(gfx::gx::TevOp::op)); - XXH3_64bits_update(&state, &input.bias, sizeof(gfx::gx::TevOp::bias)); - XXH3_64bits_update(&state, &input.scale, sizeof(gfx::gx::TevOp::scale)); - XXH3_64bits_update(&state, &input.outReg, sizeof(gfx::gx::TevOp::outReg)); - XXH3_64bits_update(&state, &input.clamp, sizeof(bool)); -} -template <> -inline void xxh3_update(XXH3_state_t& state, const gfx::gx::TevStage& input) { - xxh3_update(state, input.colorPass); - xxh3_update(state, input.alphaPass); - xxh3_update(state, input.colorOp); - xxh3_update(state, input.alphaOp); - XXH3_64bits_update(&state, &input.kcSel, sizeof(gfx::gx::TevStage::kcSel)); - XXH3_64bits_update(&state, &input.kaSel, sizeof(gfx::gx::TevStage::kaSel)); - XXH3_64bits_update(&state, &input.texCoordId, sizeof(gfx::gx::TevStage::texCoordId)); - XXH3_64bits_update(&state, &input.texMapId, sizeof(gfx::gx::TevStage::texMapId)); - XXH3_64bits_update(&state, &input.channelId, sizeof(gfx::gx::TevStage::channelId)); -} -template <> -inline void xxh3_update(XXH3_state_t& state, const gfx::gx::ColorChannelConfig& input) { - XXH3_64bits_update(&state, &input.lightingEnabled, sizeof(gfx::gx::ColorChannelConfig::lightingEnabled)); - XXH3_64bits_update(&state, &input.matSrc, sizeof(gfx::gx::ColorChannelConfig::matSrc)); - if (input.lightingEnabled) { - // Unused when lighting is disabled - XXH3_64bits_update(&state, &input.ambSrc, sizeof(gfx::gx::ColorChannelConfig::ambSrc)); - } -} -template <> -inline void xxh3_update(XXH3_state_t& state, const gfx::gx::TcgConfig& input) { - XXH3_64bits_update(&state, &input.type, sizeof(gfx::gx::TcgConfig::type)); - XXH3_64bits_update(&state, &input.src, sizeof(gfx::gx::TcgConfig::src)); - XXH3_64bits_update(&state, &input.mtx, sizeof(gfx::gx::TcgConfig::mtx)); - XXH3_64bits_update(&state, &input.postMtx, sizeof(gfx::gx::TcgConfig::postMtx)); - XXH3_64bits_update(&state, &input.normalize, sizeof(gfx::gx::TcgConfig::normalize)); -} -template <> -inline void xxh3_update(XXH3_state_t& state, const gfx::gx::AlphaCompare& input) { - XXH3_64bits_update(&state, &input.comp0, sizeof(gfx::gx::AlphaCompare::comp0)); - XXH3_64bits_update(&state, &input.ref0, sizeof(gfx::gx::AlphaCompare::ref0)); - XXH3_64bits_update(&state, &input.op, sizeof(gfx::gx::AlphaCompare::op)); - XXH3_64bits_update(&state, &input.comp1, sizeof(gfx::gx::AlphaCompare::comp1)); - XXH3_64bits_update(&state, &input.ref1, sizeof(gfx::gx::AlphaCompare::ref1)); -} -template <> -inline void xxh3_update(XXH3_state_t& state, const gfx::gx::ShaderConfig& input) { - XXH3_64bits_update(&state, &input.fogType, sizeof(gfx::gx::ShaderConfig::fogType)); - XXH3_64bits_update(&state, &input.vtxAttrs, sizeof(gfx::gx::ShaderConfig::vtxAttrs)); - XXH3_64bits_update(&state, &input.tevSwapTable, sizeof(gfx::gx::ShaderConfig::tevSwapTable)); - for (const auto& item : input.tevStages) { - if (!item) { - break; - } - xxh3_update(state, *item); - } - for (const auto& item : input.colorChannels) { - xxh3_update(state, item); - } - for (const auto& item : input.tcgs) { - xxh3_update(state, item); - } - if (input.alphaCompare) { - xxh3_update(state, input.alphaCompare); - } - XXH3_64bits_update(&state, &input.indexedAttributeCount, sizeof(gfx::gx::ShaderConfig::indexedAttributeCount)); -} -} // namespace aurora diff --git a/aurora/lib/gfx/gx_shader.cpp b/aurora/lib/gfx/gx_shader.cpp index f6b0f5f87..fff7d627f 100644 --- a/aurora/lib/gfx/gx_shader.cpp +++ b/aurora/lib/gfx/gx_shader.cpp @@ -30,30 +30,85 @@ static inline std::string_view chan_comp(GX::TevColorChan chan) noexcept { } } +static void color_arg_reg_info(GX::TevColorArg arg, const TevStage& stage, ShaderInfo& info) { + switch (arg) { + case GX::CC_C0: + case GX::CC_A0: + info.usesTevReg.set(0); + break; + case GX::CC_C1: + case GX::CC_A1: + info.usesTevReg.set(1); + break; + case GX::CC_C2: + case GX::CC_A2: + info.usesTevReg.set(2); + break; + case GX::CC_TEXC: + case GX::CC_TEXA: + info.sampledTextures.set(stage.texMapId); + break; + case GX::CC_RASC: + case GX::CC_RASA: + info.sampledColorChannels.set(stage.channelId - GX::COLOR0A0); + break; + case GX::CC_KONST: + switch (stage.kcSel) { + case GX::TEV_KCSEL_K0: + case GX::TEV_KCSEL_K0_R: + case GX::TEV_KCSEL_K0_G: + case GX::TEV_KCSEL_K0_B: + case GX::TEV_KCSEL_K0_A: + info.sampledKColors.set(0); + break; + case GX::TEV_KCSEL_K1: + case GX::TEV_KCSEL_K1_R: + case GX::TEV_KCSEL_K1_G: + case GX::TEV_KCSEL_K1_B: + case GX::TEV_KCSEL_K1_A: + info.sampledKColors.set(1); + break; + case GX::TEV_KCSEL_K2: + case GX::TEV_KCSEL_K2_R: + case GX::TEV_KCSEL_K2_G: + case GX::TEV_KCSEL_K2_B: + case GX::TEV_KCSEL_K2_A: + info.sampledKColors.set(2); + break; + case GX::TEV_KCSEL_K3: + case GX::TEV_KCSEL_K3_R: + case GX::TEV_KCSEL_K3_G: + case GX::TEV_KCSEL_K3_B: + case GX::TEV_KCSEL_K3_A: + info.sampledKColors.set(3); + break; + default: + break; + } + break; + default: + break; + } +} + static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const ShaderConfig& config, - const TevStage& stage, ShaderInfo& info) { + const TevStage& stage) { switch (arg) { case GX::CC_CPREV: return "prev.rgb"; case GX::CC_APREV: return "prev.a"; case GX::CC_C0: - info.usesTevReg.set(0); return "tevreg0.rgb"; case GX::CC_A0: - info.usesTevReg.set(0); return "tevreg0.a"; case GX::CC_C1: - info.usesTevReg.set(1); return "tevreg1.rgb"; case GX::CC_A1: - info.usesTevReg.set(1); return "tevreg1.a"; case GX::CC_C2: - info.usesTevReg.set(2); return "tevreg2.rgb"; case GX::CC_A2: - info.usesTevReg.set(2); return "tevreg2.a"; case GX::CC_TEXC: { if (stage.texMapId == GX::TEXMAP_NULL) { @@ -63,7 +118,6 @@ static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const Sha Log.report(logvisor::Fatal, FMT_STRING("invalid texture {} for stage {}"), stage.texMapId, stageIdx); unreachable(); } - info.sampledTextures.set(stage.texMapId); const auto swap = config.tevSwapTable[stage.tevSwapTex]; return fmt::format(FMT_STRING("sampled{}.{}{}{}"), stage.texMapId, chan_comp(swap.red), chan_comp(swap.green), chan_comp(swap.blue)); @@ -76,7 +130,6 @@ static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const Sha Log.report(logvisor::Fatal, FMT_STRING("invalid texture {} for stage {}"), stage.texMapId, stageIdx); unreachable(); } - info.sampledTextures.set(stage.texMapId); const auto swap = config.tevSwapTable[stage.tevSwapTex]; return fmt::format(FMT_STRING("sampled{}.{}"), stage.texMapId, chan_comp(swap.alpha)); } @@ -89,7 +142,6 @@ static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const Sha unreachable(); } u32 idx = stage.channelId - GX::COLOR0A0; - info.sampledColorChannels.set(idx); const auto swap = config.tevSwapTable[stage.tevSwapRas]; return fmt::format(FMT_STRING("rast{}.{}{}{}"), idx, chan_comp(swap.red), chan_comp(swap.green), chan_comp(swap.blue)); @@ -103,7 +155,6 @@ static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const Sha unreachable(); } u32 idx = stage.channelId - GX::COLOR0A0; - info.sampledColorChannels.set(idx); const auto swap = config.tevSwapTable[stage.tevSwapRas]; return fmt::format(FMT_STRING("rast{}.{}"), idx, chan_comp(swap.alpha)); } @@ -130,64 +181,44 @@ static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const Sha case GX::TEV_KCSEL_1_8: return "(1.0/8.0)"; case GX::TEV_KCSEL_K0: - info.sampledKColors.set(0); return "ubuf.kcolor0.rgb"; case GX::TEV_KCSEL_K1: - info.sampledKColors.set(1); return "ubuf.kcolor1.rgb"; case GX::TEV_KCSEL_K2: - info.sampledKColors.set(2); return "ubuf.kcolor2.rgb"; case GX::TEV_KCSEL_K3: - info.sampledKColors.set(3); return "ubuf.kcolor3.rgb"; case GX::TEV_KCSEL_K0_R: - info.sampledKColors.set(0); return "ubuf.kcolor0.r"; case GX::TEV_KCSEL_K1_R: - info.sampledKColors.set(1); return "ubuf.kcolor1.r"; case GX::TEV_KCSEL_K2_R: - info.sampledKColors.set(2); return "ubuf.kcolor2.r"; case GX::TEV_KCSEL_K3_R: - info.sampledKColors.set(3); return "ubuf.kcolor3.r"; case GX::TEV_KCSEL_K0_G: - info.sampledKColors.set(0); return "ubuf.kcolor0.g"; case GX::TEV_KCSEL_K1_G: - info.sampledKColors.set(1); return "ubuf.kcolor1.g"; case GX::TEV_KCSEL_K2_G: - info.sampledKColors.set(2); return "ubuf.kcolor2.g"; case GX::TEV_KCSEL_K3_G: - info.sampledKColors.set(3); return "ubuf.kcolor3.g"; case GX::TEV_KCSEL_K0_B: - info.sampledKColors.set(0); return "ubuf.kcolor0.b"; case GX::TEV_KCSEL_K1_B: - info.sampledKColors.set(1); return "ubuf.kcolor1.b"; case GX::TEV_KCSEL_K2_B: - info.sampledKColors.set(2); return "ubuf.kcolor2.b"; case GX::TEV_KCSEL_K3_B: - info.sampledKColors.set(3); return "ubuf.kcolor3.b"; case GX::TEV_KCSEL_K0_A: - info.sampledKColors.set(0); return "ubuf.kcolor0.a"; case GX::TEV_KCSEL_K1_A: - info.sampledKColors.set(1); return "ubuf.kcolor1.a"; case GX::TEV_KCSEL_K2_A: - info.sampledKColors.set(2); return "ubuf.kcolor2.a"; case GX::TEV_KCSEL_K3_A: - info.sampledKColors.set(3); return "ubuf.kcolor3.a"; default: Log.report(logvisor::Fatal, FMT_STRING("invalid kcSel {}"), stage.kcSel); @@ -202,19 +233,68 @@ static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const Sha } } +static void alpha_arg_reg_info(GX::TevAlphaArg arg, const TevStage& stage, ShaderInfo& info) { + switch (arg) { + case GX::CA_A0: + info.usesTevReg.set(0); + break; + case GX::CA_A1: + info.usesTevReg.set(1); + break; + case GX::CA_A2: + info.usesTevReg.set(2); + break; + case GX::CA_TEXA: + info.sampledTextures.set(stage.texMapId); + break; + case GX::CA_RASA: + info.sampledColorChannels.set(stage.channelId - GX::COLOR0A0); + break; + case GX::CA_KONST: + switch (stage.kaSel) { + case GX::TEV_KASEL_K0_R: + case GX::TEV_KASEL_K0_G: + case GX::TEV_KASEL_K0_B: + case GX::TEV_KASEL_K0_A: + info.sampledKColors.set(0); + break; + case GX::TEV_KASEL_K1_R: + case GX::TEV_KASEL_K1_G: + case GX::TEV_KASEL_K1_B: + case GX::TEV_KASEL_K1_A: + info.sampledKColors.set(1); + break; + case GX::TEV_KASEL_K2_R: + case GX::TEV_KASEL_K2_G: + case GX::TEV_KASEL_K2_B: + case GX::TEV_KASEL_K2_A: + info.sampledKColors.set(2); + break; + case GX::TEV_KASEL_K3_R: + case GX::TEV_KASEL_K3_G: + case GX::TEV_KASEL_K3_B: + case GX::TEV_KASEL_K3_A: + info.sampledKColors.set(3); + break; + default: + break; + } + break; + default: + break; + } +} + static std::string alpha_arg_reg(GX::TevAlphaArg arg, size_t stageIdx, const ShaderConfig& config, - const TevStage& stage, ShaderInfo& info) { + const TevStage& stage) { switch (arg) { case GX::CA_APREV: return "prev.a"; case GX::CA_A0: - info.usesTevReg.set(0); return "tevreg0.a"; case GX::CA_A1: - info.usesTevReg.set(1); return "tevreg1.a"; case GX::CA_A2: - info.usesTevReg.set(2); return "tevreg2.a"; case GX::CA_TEXA: { if (stage.texMapId == GX::TEXMAP_NULL) { @@ -224,7 +304,6 @@ static std::string alpha_arg_reg(GX::TevAlphaArg arg, size_t stageIdx, const Sha Log.report(logvisor::Fatal, FMT_STRING("invalid texture {} for stage {}"), stage.texMapId, stageIdx); unreachable(); } - info.sampledTextures.set(stage.texMapId); const auto swap = config.tevSwapTable[stage.tevSwapTex]; return fmt::format(FMT_STRING("sampled{}.{}"), stage.texMapId, chan_comp(swap.alpha)); } @@ -237,7 +316,6 @@ static std::string alpha_arg_reg(GX::TevAlphaArg arg, size_t stageIdx, const Sha unreachable(); } u32 idx = stage.channelId - GX::COLOR0A0; - info.sampledColorChannels.set(idx); const auto swap = config.tevSwapTable[stage.tevSwapRas]; return fmt::format(FMT_STRING("rast{}.{}"), idx, chan_comp(swap.alpha)); } @@ -260,52 +338,36 @@ static std::string alpha_arg_reg(GX::TevAlphaArg arg, size_t stageIdx, const Sha case GX::TEV_KASEL_1_8: return "(1.0/8.0)"; case GX::TEV_KASEL_K0_R: - info.sampledKColors.set(0); return "ubuf.kcolor0.r"; case GX::TEV_KASEL_K1_R: - info.sampledKColors.set(1); return "ubuf.kcolor1.r"; case GX::TEV_KASEL_K2_R: - info.sampledKColors.set(2); return "ubuf.kcolor2.r"; case GX::TEV_KASEL_K3_R: - info.sampledKColors.set(3); return "ubuf.kcolor3.r"; case GX::TEV_KASEL_K0_G: - info.sampledKColors.set(0); return "ubuf.kcolor0.g"; case GX::TEV_KASEL_K1_G: - info.sampledKColors.set(1); return "ubuf.kcolor1.g"; case GX::TEV_KASEL_K2_G: - info.sampledKColors.set(2); return "ubuf.kcolor2.g"; case GX::TEV_KASEL_K3_G: - info.sampledKColors.set(3); return "ubuf.kcolor3.g"; case GX::TEV_KASEL_K0_B: - info.sampledKColors.set(0); return "ubuf.kcolor0.b"; case GX::TEV_KASEL_K1_B: - info.sampledKColors.set(1); return "ubuf.kcolor1.b"; case GX::TEV_KASEL_K2_B: - info.sampledKColors.set(2); return "ubuf.kcolor2.b"; case GX::TEV_KASEL_K3_B: - info.sampledKColors.set(3); return "ubuf.kcolor3.b"; case GX::TEV_KASEL_K0_A: - info.sampledKColors.set(0); return "ubuf.kcolor0.a"; case GX::TEV_KASEL_K1_A: - info.sampledKColors.set(1); return "ubuf.kcolor1.a"; case GX::TEV_KASEL_K2_A: - info.sampledKColors.set(2); return "ubuf.kcolor2.a"; case GX::TEV_KASEL_K3_A: - info.sampledKColors.set(3); return "ubuf.kcolor3.a"; default: Log.report(logvisor::Fatal, FMT_STRING("invalid kaSel {}"), stage.kaSel); @@ -346,22 +408,23 @@ static std::string_view tev_bias(GX::TevBias bias) { } } -static std::string alpha_compare(GX::Compare comp, float ref, bool& valid) { +static std::string alpha_compare(GX::Compare comp, u8 ref, bool& valid) { + const float fref = ref / 255.f; switch (comp) { case GX::NEVER: return "false"; case GX::LESS: - return fmt::format(FMT_STRING("(prev.a < {}f)"), ref); + return fmt::format(FMT_STRING("(prev.a < {}f)"), fref); case GX::LEQUAL: - return fmt::format(FMT_STRING("(prev.a <= {}f)"), ref); + return fmt::format(FMT_STRING("(prev.a <= {}f)"), fref); case GX::EQUAL: - return fmt::format(FMT_STRING("(prev.a == {}f)"), ref); + return fmt::format(FMT_STRING("(prev.a == {}f)"), fref); case GX::NEQUAL: - return fmt::format(FMT_STRING("(prev.a != {}f)"), ref); + return fmt::format(FMT_STRING("(prev.a != {}f)"), fref); case GX::GEQUAL: - return fmt::format(FMT_STRING("(prev.a >= {}f)"), ref); + return fmt::format(FMT_STRING("(prev.a >= {}f)"), fref); case GX::GREATER: - return fmt::format(FMT_STRING("(prev.a > {}f)"), ref); + return fmt::format(FMT_STRING("(prev.a > {}f)"), fref); case GX::ALWAYS: valid = false; return "true"; @@ -422,7 +485,106 @@ constexpr std::array VtxAttributeNames{ "pos_mtx_array", "nrm_mtx_array", "tex_mtx_array", "light_array", "nbt", }; -std::pair build_shader(const ShaderConfig& config) noexcept { +ShaderInfo build_shader_info(const ShaderConfig& config) noexcept { + // const auto hash = xxh3_hash(config); + // const auto it = g_gxCachedShaders.find(hash); + // if (it != g_gxCachedShaders.end()) { + // return it->second.second; + // } + + ShaderInfo info{ + .uniformSize = 64 * 3, // mv, mvInv, proj + }; + for (int i = 0; i < config.tevStageCount; ++i) { + const auto& stage = config.tevStages[i]; + // Color pass + switch (stage.colorOp.outReg) { + case GX::TEVREG0: + info.usesTevReg.set(0); + break; + case GX::TEVREG1: + info.usesTevReg.set(1); + break; + case GX::TEVREG2: + info.usesTevReg.set(2); + break; + default: + break; + } + color_arg_reg_info(stage.colorPass.a, stage, info); + color_arg_reg_info(stage.colorPass.b, stage, info); + color_arg_reg_info(stage.colorPass.c, stage, info); + color_arg_reg_info(stage.colorPass.d, stage, info); + + // Alpha pass + switch (stage.alphaOp.outReg) { + case GX::TEVREG0: + info.usesTevReg.set(0); + break; + case GX::TEVREG1: + info.usesTevReg.set(1); + break; + case GX::TEVREG2: + info.usesTevReg.set(2); + break; + default: + break; + } + alpha_arg_reg_info(stage.alphaPass.a, stage, info); + alpha_arg_reg_info(stage.alphaPass.b, stage, info); + alpha_arg_reg_info(stage.alphaPass.c, stage, info); + alpha_arg_reg_info(stage.alphaPass.d, stage, info); + } + info.uniformSize += info.usesTevReg.count() * 16; + for (int i = 0; i < info.sampledColorChannels.size(); ++i) { + if (info.sampledColorChannels.test(i)) { + info.uniformSize += 32; + if (config.colorChannels[i].lightingEnabled) { + info.uniformSize += (80 * GX::MaxLights) + 16; + } + } + } + info.uniformSize += info.sampledKColors.count() * 16; + for (int i = 0; i < info.sampledTextures.size(); ++i) { + if (!info.sampledTextures.test(i)) { + continue; + } + const auto& tcg = config.tcgs[i]; + if (tcg.mtx != GX::IDENTITY) { + u32 texMtxIdx = (tcg.mtx - GX::TEXMTX0) / 3; + info.usesTexMtx.set(texMtxIdx); + info.texMtxTypes[texMtxIdx] = tcg.type; + } + if (tcg.postMtx != GX::PTIDENTITY) { + u32 postMtxIdx = (tcg.postMtx - GX::PTTEXMTX0) / 3; + info.usesPTTexMtx.set(postMtxIdx); + } + } + for (int i = 0; i < info.usesTexMtx.size(); ++i) { + if (info.usesTexMtx.test(i)) { + switch (info.texMtxTypes[i]) { + case GX::TG_MTX2x4: + info.uniformSize += 32; + break; + case GX::TG_MTX3x4: + info.uniformSize += 64; + break; + default: + break; + } + } + } + info.uniformSize += info.usesPTTexMtx.count() * 64; + if (config.fogType != GX::FOG_NONE) { + info.usesFog = true; + info.uniformSize += 32; + } + info.uniformSize += info.sampledTextures.count() * 4; + info.uniformSize = align_uniform(info.uniformSize); + return info; +} + +wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& info) noexcept { const auto hash = xxh3_hash(config); const auto it = g_gxCachedShaders.find(hash); if (it != g_gxCachedShaders.end()) { @@ -432,44 +594,38 @@ std::pair build_shader(const ShaderConfig& confi unreachable(); } #endif - return it->second; + return it->second.first; } Log.report(logvisor::Info, FMT_STRING("Shader config (hash {:x}):"), hash); - ShaderInfo info{ - .uniformSize = 64 * 3, // mv, mvInv, proj - }; { - for (int i = 0; i < config.tevStages.size(); ++i) { + for (int i = 0; i < config.tevStageCount; ++i) { const auto& stage = config.tevStages[i]; - if (!stage) { - break; - } 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); + 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]; @@ -594,85 +750,70 @@ std::pair build_shader(const ShaderConfig& confi std::string fragmentFnPre; std::string fragmentFn; - for (size_t idx = 0; const auto& stage : config.tevStages) { - if (!stage) { - break; - } + for (u32 idx = 0; idx < config.tevStageCount; ++idx) { + const auto& stage = config.tevStages[idx]; { std::string outReg; - switch (stage->colorOp.outReg) { + switch (stage.colorOp.outReg) { case GX::TEVPREV: outReg = "prev"; break; case GX::TEVREG0: outReg = "tevreg0"; - info.usesTevReg.set(0); break; case GX::TEVREG1: outReg = "tevreg1"; - info.usesTevReg.set(1); break; case GX::TEVREG2: outReg = "tevreg2"; - info.usesTevReg.set(2); break; default: - Log.report(logvisor::Fatal, FMT_STRING("invalid colorOp outReg {}"), stage->colorOp.outReg); + Log.report(logvisor::Fatal, FMT_STRING("invalid colorOp outReg {}"), stage.colorOp.outReg); } - std::string op = - fmt::format(FMT_STRING("({3} {4} ((1.0 - {2}) * {0} + {2} * {1}){5}){6}"), - color_arg_reg(stage->colorPass.a, idx, config, *stage, info), - color_arg_reg(stage->colorPass.b, idx, config, *stage, info), - color_arg_reg(stage->colorPass.c, idx, config, *stage, info), - color_arg_reg(stage->colorPass.d, idx, config, *stage, info), tev_op(stage->colorOp.op), - tev_bias(stage->colorOp.bias), tev_scale(stage->colorOp.scale)); - if (stage->colorOp.clamp) { + std::string op = fmt::format( + FMT_STRING("({3} {4} ((1.0 - {2}) * {0} + {2} * {1}){5}){6}"), + color_arg_reg(stage.colorPass.a, idx, config, stage), color_arg_reg(stage.colorPass.b, idx, config, stage), + color_arg_reg(stage.colorPass.c, idx, config, stage), color_arg_reg(stage.colorPass.d, idx, config, stage), + tev_op(stage.colorOp.op), tev_bias(stage.colorOp.bias), tev_scale(stage.colorOp.scale)); + if (stage.colorOp.clamp) { op = fmt::format(FMT_STRING("clamp(vec3({}), vec3(0.0), vec3(1.0))"), op); } fragmentFn += fmt::format(FMT_STRING("\n {0} = vec4({1}, {0}.a);"), outReg, op); } { std::string outReg; - switch (stage->alphaOp.outReg) { + switch (stage.alphaOp.outReg) { case GX::TEVPREV: outReg = "prev.a"; break; case GX::TEVREG0: outReg = "tevreg0.a"; - info.usesTevReg.set(0); break; case GX::TEVREG1: outReg = "tevreg1.a"; - info.usesTevReg.set(1); break; case GX::TEVREG2: outReg = "tevreg2.a"; - info.usesTevReg.set(2); break; default: - Log.report(logvisor::Fatal, FMT_STRING("invalid alphaOp outReg {}"), stage->alphaOp.outReg); + Log.report(logvisor::Fatal, FMT_STRING("invalid alphaOp outReg {}"), stage.alphaOp.outReg); } - std::string op = - fmt::format(FMT_STRING("({3} {4} ((1.0 - {2}) * {0} + {2} * {1}){5}){6}"), - alpha_arg_reg(stage->alphaPass.a, idx, config, *stage, info), - alpha_arg_reg(stage->alphaPass.b, idx, config, *stage, info), - alpha_arg_reg(stage->alphaPass.c, idx, config, *stage, info), - alpha_arg_reg(stage->alphaPass.d, idx, config, *stage, info), tev_op(stage->alphaOp.op), - tev_bias(stage->alphaOp.bias), tev_scale(stage->alphaOp.scale)); - if (stage->alphaOp.clamp) { + std::string op = fmt::format( + FMT_STRING("({3} {4} ((1.0 - {2}) * {0} + {2} * {1}){5}){6}"), + alpha_arg_reg(stage.alphaPass.a, idx, config, stage), alpha_arg_reg(stage.alphaPass.b, idx, config, stage), + alpha_arg_reg(stage.alphaPass.c, idx, config, stage), alpha_arg_reg(stage.alphaPass.d, idx, config, stage), + tev_op(stage.alphaOp.op), tev_bias(stage.alphaOp.bias), tev_scale(stage.alphaOp.scale)); + if (stage.alphaOp.clamp) { op = fmt::format(FMT_STRING("clamp({}, 0.0, 1.0)"), op); } fragmentFn += fmt::format(FMT_STRING("\n {0} = {1};"), outReg, op); } - idx++; } for (int i = 0; i < info.usesTevReg.size(); ++i) { - if (!info.usesTevReg.test(i)) { - continue; + if (info.usesTevReg.test(i)) { + uniBufAttrs += fmt::format(FMT_STRING("\n tevreg{}: vec4;"), i); + fragmentFnPre += fmt::format(FMT_STRING("\n var tevreg{0} = ubuf.tevreg{0};"), i); } - uniBufAttrs += fmt::format(FMT_STRING("\n tevreg{}: vec4;"), i); - fragmentFnPre += fmt::format(FMT_STRING("\n var tevreg{0} = ubuf.tevreg{0};"), i); - info.uniformSize += 16; } bool addedLightStruct = false; for (int i = 0; i < info.sampledColorChannels.size(); ++i) { @@ -682,7 +823,6 @@ std::pair build_shader(const ShaderConfig& confi uniBufAttrs += fmt::format(FMT_STRING("\n cc{0}_amb: vec4;"), i); uniBufAttrs += fmt::format(FMT_STRING("\n cc{0}_mat: vec4;"), i); - info.uniformSize += 32; if (config.colorChannels[i].lightingEnabled) { if (!addedLightStruct) { @@ -700,7 +840,6 @@ std::pair build_shader(const ShaderConfig& confi uniBufAttrs += fmt::format(FMT_STRING("\n lights{}: array;"), i, GX::MaxLights); uniBufAttrs += fmt::format(FMT_STRING("\n lighting_ambient{}: vec4;"), i); - info.uniformSize += (80 * GX::MaxLights) + 16; vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) cc{}: vec4;"), vtxOutIdx++, i); vtxXfrAttrs += fmt::format(FMT_STRING(R"""( @@ -734,11 +873,9 @@ std::pair build_shader(const ShaderConfig& confi } } for (int i = 0; i < info.sampledKColors.size(); ++i) { - if (!info.sampledKColors.test(i)) { - continue; + if (info.sampledKColors.test(i)) { + uniBufAttrs += fmt::format(FMT_STRING("\n kcolor{}: vec4;"), i); } - uniBufAttrs += fmt::format(FMT_STRING("\n kcolor{}: vec4;"), i); - info.uniformSize += 16; } size_t texBindIdx = 0; for (int i = 0; i < info.sampledTextures.size(); ++i) { @@ -763,8 +900,6 @@ std::pair build_shader(const ShaderConfig& confi vtxXfrAttrs += fmt::format(FMT_STRING("\n var tc{0}_tmp = tc{0}.xyz;"), i); } else { u32 texMtxIdx = (tcg.mtx - GX::TEXMTX0) / 3; - info.usesTexMtx.set(texMtxIdx); - info.texMtxTypes[texMtxIdx] = tcg.type; vtxXfrAttrs += fmt::format(FMT_STRING("\n var tc{0}_tmp = ubuf.texmtx{1} * tc{0};"), i, texMtxIdx); } if (tcg.normalize) { @@ -774,7 +909,6 @@ std::pair build_shader(const ShaderConfig& confi vtxXfrAttrs += fmt::format(FMT_STRING("\n var tc{0}_proj = tc{0}_tmp;"), i); } else { u32 postMtxIdx = (tcg.postMtx - GX::PTTEXMTX0) / 3; - info.usesPTTexMtx.set(postMtxIdx); vtxXfrAttrs += fmt::format(FMT_STRING("\n var tc{0}_proj = ubuf.postmtx{1} * vec4(tc{0}_tmp.xyz, 1.0);"), i, postMtxIdx); } @@ -783,33 +917,26 @@ std::pair build_shader(const ShaderConfig& confi FMT_STRING("\n var sampled{0} = textureSampleBias(tex{0}, tex{0}_samp, in.tex{0}_uv, ubuf.tex{0}_lod);"), i); } for (int i = 0; i < info.usesTexMtx.size(); ++i) { - if (!info.usesTexMtx.test(i)) { - continue; - } - switch (info.texMtxTypes[i]) { - case GX::TG_MTX2x4: - uniBufAttrs += fmt::format(FMT_STRING("\n texmtx{}: mat4x2;"), i); - info.uniformSize += 32; - break; - case GX::TG_MTX3x4: - uniBufAttrs += fmt::format(FMT_STRING("\n texmtx{}: mat4x3;"), i); - info.uniformSize += 64; - break; - default: - Log.report(logvisor::Fatal, FMT_STRING("unhandled tex mtx type {}"), info.texMtxTypes[i]); - unreachable(); + if (info.usesTexMtx.test(i)) { + switch (info.texMtxTypes[i]) { + case GX::TG_MTX2x4: + uniBufAttrs += fmt::format(FMT_STRING("\n texmtx{}: mat4x2;"), i); + break; + case GX::TG_MTX3x4: + uniBufAttrs += fmt::format(FMT_STRING("\n texmtx{}: mat4x3;"), i); + break; + default: + Log.report(logvisor::Fatal, FMT_STRING("unhandled tex mtx type {}"), info.texMtxTypes[i]); + unreachable(); + } } } for (int i = 0; i < info.usesPTTexMtx.size(); ++i) { - if (!info.usesPTTexMtx.test(i)) { - continue; + if (info.usesPTTexMtx.test(i)) { + uniBufAttrs += fmt::format(FMT_STRING("\n postmtx{}: mat4x3;"), i); } - uniBufAttrs += fmt::format(FMT_STRING("\n postmtx{}: mat4x3;"), i); - info.uniformSize += 64; } - if (config.fogType != GX::FOG_NONE) { - info.usesFog = true; - + if (info.usesFog) { uniformPre += "\n" "struct Fog {\n" @@ -820,7 +947,6 @@ std::pair build_shader(const ShaderConfig& confi " pad: f32;\n" "}"; uniBufAttrs += "\n fog: Fog;"; - info.uniformSize += 32; fragmentFn += "\n var fogF = clamp((ubuf.fog.a / (ubuf.fog.b - in.pos.z)) - ubuf.fog.c, 0.0, 1.0);"; switch (config.fogType) { @@ -857,7 +983,6 @@ std::pair build_shader(const ShaderConfig& confi continue; } uniBufAttrs += fmt::format(FMT_STRING("\n tex{}_lod: f32;"), i); - info.uniformSize += 4; sampBindings += fmt::format(FMT_STRING("\n@group(1) @binding({})\n" "var tex{}_samp: sampler;"), @@ -939,13 +1064,12 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4 {{ }; auto shader = gpu::g_device.CreateShaderModule(&shaderDescriptor); - info.uniformSize = align_uniform(info.uniformSize); auto pair = std::make_pair(std::move(shader), info); g_gxCachedShaders.emplace(hash, pair); #ifndef NDEBUG g_gxCachedShaderConfigs.emplace(hash, config); #endif - return pair; + return pair.first; } } // namespace aurora::gfx::gx diff --git a/aurora/lib/gfx/model/shader.cpp b/aurora/lib/gfx/model/shader.cpp index 648a43f64..c92a42c41 100644 --- a/aurora/lib/gfx/model/shader.cpp +++ b/aurora/lib/gfx/model/shader.cpp @@ -40,7 +40,7 @@ static inline void read_vert(ByteBuffer& out, const u8* data) noexcept { static absl::flat_hash_map> sCachedDisplayLists; void queue_surface(const u8* dlStart, u32 dlSize) noexcept { - const auto hash = xxh3_hash(dlStart, dlSize, 0); + const auto hash = xxh3_hash_s(dlStart, dlSize, 0); Range vertRange, idxRange; u32 numIndices = 0; auto it = sCachedDisplayLists.find(hash); @@ -165,13 +165,15 @@ void queue_surface(const u8* dlStart, u32 dlSize) noexcept { } model::PipelineConfig config{}; + populate_pipeline_config(config, GX::TRIANGLES); + const auto info = gx::build_shader_info(config.shaderConfig); const gx::BindGroupRanges ranges{ .vtxDataRange = sVtxRange, .nrmDataRange = sNrmRange, .tcDataRange = sTcRange, .packedTcDataRange = sPackedTcRange, }; - const auto info = populate_pipeline_config(config, GX::TRIANGLES, ranges); + const auto bindGroups = gx::build_bind_groups(info, config.shaderConfig, ranges); const auto pipeline = pipeline_ref(config); push_draw_command(model::DrawData{ @@ -181,7 +183,7 @@ void queue_surface(const u8* dlStart, u32 dlSize) noexcept { .dataRanges = ranges, .uniformRange = build_uniform(info), .indexCount = numIndices, - .bindGroups = info.bindGroups, + .bindGroups = bindGroups, .dstAlpha = gx::g_gxState.dstAlpha, }); } @@ -189,9 +191,10 @@ void queue_surface(const u8* dlStart, u32 dlSize) noexcept { State construct_state() { return {}; } wgpu::RenderPipeline create_pipeline(const State& state, [[maybe_unused]] PipelineConfig config) { - const auto [shader, info] = build_shader(config.shaderConfig); + const auto info = build_shader_info(config.shaderConfig); // TODO remove + const auto shader = build_shader(config.shaderConfig, info); - std::array vtxAttrs; + std::array vtxAttrs{}; auto [num4xAttr, rem] = std::div(config.shaderConfig.indexedAttributeCount, 4); u32 num2xAttr = 0; if (rem > 2) { @@ -246,8 +249,8 @@ void render(const State& state, const DrawData& data, const wgpu::RenderPassEnco } pass.SetVertexBuffer(0, g_vertexBuffer, data.vertRange.offset, data.vertRange.size); pass.SetIndexBuffer(g_indexBuffer, wgpu::IndexFormat::Uint16, data.idxRange.offset, data.idxRange.size); - if (data.dstAlpha) { - const wgpu::Color color{0.f, 0.f, 0.f, *data.dstAlpha}; + if (data.dstAlpha != UINT32_MAX) { + const wgpu::Color color{0.f, 0.f, 0.f, data.dstAlpha / 255.f}; pass.SetBlendConstant(&color); } pass.DrawIndexed(data.indexCount); diff --git a/aurora/lib/gfx/model/shader.hpp b/aurora/lib/gfx/model/shader.hpp index 40e90c2d8..8c876b0e5 100644 --- a/aurora/lib/gfx/model/shader.hpp +++ b/aurora/lib/gfx/model/shader.hpp @@ -12,7 +12,7 @@ struct DrawData { Range uniformRange; uint32_t indexCount; gx::GXBindGroups bindGroups; - std::optional dstAlpha; + u32 dstAlpha; }; struct PipelineConfig : gx::PipelineConfig {}; diff --git a/aurora/lib/gfx/movie_player/shader.hpp b/aurora/lib/gfx/movie_player/shader.hpp index 2b57b895b..b794ea5c7 100644 --- a/aurora/lib/gfx/movie_player/shader.hpp +++ b/aurora/lib/gfx/movie_player/shader.hpp @@ -11,8 +11,9 @@ struct DrawData { }; struct PipelineConfig { - // nothing + u32 pad = 0; // empty }; +static_assert(std::has_unique_object_representations_v); static const std::array INITIAL_PIPELINES{ PipelineConfig{}, }; diff --git a/aurora/lib/gfx/stream.cpp b/aurora/lib/gfx/stream.cpp index 6ee2b798a..ffa55a519 100644 --- a/aurora/lib/gfx/stream.cpp +++ b/aurora/lib/gfx/stream.cpp @@ -128,6 +128,14 @@ void GXTexCoord2f32(const zeus::CVector2f& uv) noexcept { check_attr_order(GX::VA_TEX0); sStreamState->vertexBuffer.append(&uv, 8); } +void GXPosition1x16(u16 idx) noexcept { + check_attr_order(GX::VA_POS); + // keep aligned + if (sStreamState->vertexBuffer.size() % 4 != 0) { + sStreamState->vertexBuffer.append_zeroes(4 - (sStreamState->vertexBuffer.size() % 4)); + } + sStreamState->vertexBuffer.append(&idx, 2); +} void GXEnd() noexcept { if (sStreamState->vertexCount == 0) { sStreamState.reset(); @@ -136,7 +144,8 @@ void GXEnd() noexcept { const auto vertRange = aurora::gfx::push_verts(sStreamState->vertexBuffer.data(), sStreamState->vertexBuffer.size()); const auto indexRange = aurora::gfx::push_indices(aurora::ArrayRef{sStreamState->indices}); aurora::gfx::stream::PipelineConfig config{}; - const auto info = populate_pipeline_config(config, GX::TRIANGLES, {}); + populate_pipeline_config(config, GX::TRIANGLES); + const auto info = aurora::gfx::gx::build_shader_info(config.shaderConfig); const auto pipeline = aurora::gfx::pipeline_ref(config); aurora::gfx::push_draw_command(aurora::gfx::stream::DrawData{ .pipeline = pipeline, @@ -144,7 +153,7 @@ void GXEnd() noexcept { .uniformRange = build_uniform(info), .indexRange = indexRange, .indexCount = static_cast(sStreamState->indices.size()), - .bindGroups = info.bindGroups, + .bindGroups = aurora::gfx::gx::build_bind_groups(info, config.shaderConfig, {}), .dstAlpha = g_gxState.dstAlpha, }); sStreamState.reset(); diff --git a/aurora/lib/gfx/stream/shader.cpp b/aurora/lib/gfx/stream/shader.cpp index 3ec4fbabc..0f12626e0 100644 --- a/aurora/lib/gfx/stream/shader.cpp +++ b/aurora/lib/gfx/stream/shader.cpp @@ -12,7 +12,8 @@ static logvisor::Module Log("aurora::gfx::stream"); using gpu::g_device; wgpu::RenderPipeline create_pipeline(const State& state, [[maybe_unused]] PipelineConfig config) { - const auto [shader, info] = build_shader(config.shaderConfig); + const auto info = build_shader_info(config.shaderConfig); // TODO remove + const auto shader = build_shader(config.shaderConfig, info); std::array attributes{}; attributes[0] = wgpu::VertexAttribute{ @@ -76,8 +77,8 @@ void render(const State& state, const DrawData& data, const wgpu::RenderPassEnco } pass.SetVertexBuffer(0, g_vertexBuffer, data.vertRange.offset, data.vertRange.size); pass.SetIndexBuffer(g_indexBuffer, wgpu::IndexFormat::Uint16, data.indexRange.offset, data.indexRange.size); - if (data.dstAlpha) { - const wgpu::Color color{0.f, 0.f, 0.f, *data.dstAlpha}; + if (data.dstAlpha != UINT32_MAX) { + const wgpu::Color color{0.f, 0.f, 0.f, data.dstAlpha / 255.f}; pass.SetBlendConstant(&color); } pass.DrawIndexed(data.indexCount); diff --git a/aurora/lib/gfx/stream/shader.hpp b/aurora/lib/gfx/stream/shader.hpp index 41760bb74..b79afe403 100644 --- a/aurora/lib/gfx/stream/shader.hpp +++ b/aurora/lib/gfx/stream/shader.hpp @@ -11,7 +11,7 @@ struct DrawData { Range indexRange; uint32_t indexCount; gx::GXBindGroups bindGroups; - std::optional dstAlpha; + u32 dstAlpha; }; struct PipelineConfig : public gx::PipelineConfig {}; diff --git a/aurora/lib/gfx/textured_quad/shader.cpp b/aurora/lib/gfx/textured_quad/shader.cpp deleted file mode 100644 index 30625bfe4..000000000 --- a/aurora/lib/gfx/textured_quad/shader.cpp +++ /dev/null @@ -1,389 +0,0 @@ -#include "shader.hpp" - -#include "../gx.hpp" -#include "../../gpu.hpp" - -#include -#include - -namespace aurora::gfx::textured_quad { -static logvisor::Module Log("aurora::gfx::textured_quad"); - -using gpu::g_device; -using gpu::g_graphicsConfig; -using gpu::utils::make_vertex_attributes; -using gpu::utils::make_vertex_buffer_layout; -using gpu::utils::make_vertex_state; - -State construct_state() { - wgpu::ShaderModuleWGSLDescriptor wgslDescriptor{}; - wgslDescriptor.source = R"""( -struct Uniform { - xf: mat4x4; - color: vec4; - lod: f32; -}; -@group(0) @binding(0) -var ubuf: Uniform; -@group(0) @binding(1) -var texture_sampler: sampler; -@group(1) @binding(0) -var texture: texture_2d; - -struct VertexOutput { - @builtin(position) pos: vec4; - @location(0) uv: vec2; -}; - -@stage(vertex) -fn vs_main(@location(0) in_pos: vec3, @location(1) in_uv: vec2) -> VertexOutput { - var out: VertexOutput; - out.pos = ubuf.xf * vec4(in_pos, 1.0); - out.uv = in_uv; - return out; -} - -@stage(fragment) -fn fs_main(in: VertexOutput) -> @location(0) vec4 { - return ubuf.color * textureSampleBias(texture, texture_sampler, in.uv, ubuf.lod); -} -)"""; - const auto shaderDescriptor = wgpu::ShaderModuleDescriptor{ - .nextInChain = &wgslDescriptor, - .label = "Textured Quad Shader", - }; - auto shader = g_device.CreateShaderModule(&shaderDescriptor); - - wgpu::SupportedLimits limits; - g_device.GetLimits(&limits); - const auto uniform_alignment = limits.limits.minUniformBufferOffsetAlignment; - const auto uniform_size = ALIGN(sizeof(Uniform), uniform_alignment); - - const std::array uniformLayoutEntries{ - wgpu::BindGroupLayoutEntry{ - .binding = 0, - .visibility = wgpu::ShaderStage::Vertex | wgpu::ShaderStage::Fragment, - .buffer = - wgpu::BufferBindingLayout{ - .type = wgpu::BufferBindingType::Uniform, - .hasDynamicOffset = true, - .minBindingSize = uniform_size, - }, - }, - wgpu::BindGroupLayoutEntry{ - .binding = 1, - .visibility = wgpu::ShaderStage::Fragment, - .sampler = - wgpu::SamplerBindingLayout{ - .type = wgpu::SamplerBindingType::Filtering, - }, - }, - }; - const auto uniformLayoutDescriptor = wgpu::BindGroupLayoutDescriptor{ - .label = "Textured Quad Uniform Bind Group Layout", - .entryCount = uniformLayoutEntries.size(), - .entries = uniformLayoutEntries.data(), - }; - auto uniformLayout = g_device.CreateBindGroupLayout(&uniformLayoutDescriptor); - - const auto samplerDescriptor = wgpu::SamplerDescriptor{ - .addressModeU = wgpu::AddressMode::Repeat, - .addressModeV = wgpu::AddressMode::Repeat, - .addressModeW = wgpu::AddressMode::Repeat, - .magFilter = wgpu::FilterMode::Linear, - .minFilter = wgpu::FilterMode::Linear, - .mipmapFilter = wgpu::FilterMode::Linear, - .maxAnisotropy = g_graphicsConfig.textureAnistropy, - }; - auto sampler = g_device.CreateSampler(&samplerDescriptor); - - const std::array uniformBindGroupEntries{ - wgpu::BindGroupEntry{ - .binding = 0, - .buffer = g_uniformBuffer, - .size = uniform_size, - }, - wgpu::BindGroupEntry{ - .binding = 1, - .sampler = sampler, - }, - }; - const auto uniformBindGroupDescriptor = wgpu::BindGroupDescriptor{ - .label = "Textured Quad Uniform Bind Group", - .layout = uniformLayout, - .entryCount = uniformBindGroupEntries.size(), - .entries = uniformBindGroupEntries.data(), - }; - auto uniformBindGroup = g_device.CreateBindGroup(&uniformBindGroupDescriptor); - - const auto textureBinding = wgpu::TextureBindingLayout{ - .sampleType = wgpu::TextureSampleType::Float, - .viewDimension = wgpu::TextureViewDimension::e2D, - }; - const std::array textureLayoutEntries{ - wgpu::BindGroupLayoutEntry{ - .binding = 0, - .visibility = wgpu::ShaderStage::Fragment, - .texture = textureBinding, - }, - }; - const auto textureLayoutDescriptor = wgpu::BindGroupLayoutDescriptor{ - .label = "Textured Quad Texture Bind Group Layout", - .entryCount = textureLayoutEntries.size(), - .entries = textureLayoutEntries.data(), - }; - auto textureLayout = g_device.CreateBindGroupLayout(&textureLayoutDescriptor); - - const std::array bindGroupLayouts{ - uniformLayout, - textureLayout, - }; - const auto pipelineLayoutDescriptor = wgpu::PipelineLayoutDescriptor{ - .label = "Textured Quad Pipeline Layout", - .bindGroupLayoutCount = bindGroupLayouts.size(), - .bindGroupLayouts = bindGroupLayouts.data(), - }; - auto pipelineLayout = g_device.CreatePipelineLayout(&pipelineLayoutDescriptor); - - return { - .shader = shader, - .uniformLayout = uniformLayout, - .uniformBindGroup = uniformBindGroup, - .textureLayout = textureLayout, - .sampler = sampler, - .pipelineLayout = pipelineLayout, - }; -} - -wgpu::RenderPipeline create_pipeline(const State& state, [[maybe_unused]] PipelineConfig config) { - const auto attributes = - make_vertex_attributes(std::array{wgpu::VertexFormat::Float32x3, wgpu::VertexFormat::Float32x2}); - const std::array vertexBuffers{make_vertex_buffer_layout(sizeof(Vert), attributes)}; - - wgpu::CompareFunction depthCompare; - switch (config.zComparison) { - case ZComp::Never: - depthCompare = wgpu::CompareFunction::Never; - break; - case ZComp::Less: - depthCompare = wgpu::CompareFunction::Less; - break; - case ZComp::Equal: - depthCompare = wgpu::CompareFunction::Equal; - break; - case ZComp::LEqual: - depthCompare = wgpu::CompareFunction::LessEqual; - break; - case ZComp::Greater: - depthCompare = wgpu::CompareFunction::Greater; - break; - case ZComp::NEqual: - depthCompare = wgpu::CompareFunction::NotEqual; - break; - case ZComp::GEqual: - depthCompare = wgpu::CompareFunction::GreaterEqual; - break; - case ZComp::Always: - depthCompare = wgpu::CompareFunction::Always; - break; - } - const auto depthStencil = wgpu::DepthStencilState{ - .format = g_graphicsConfig.depthFormat, - .depthWriteEnabled = config.zTest, - .depthCompare = depthCompare, - }; - - bool alphaWrite = false; - wgpu::BlendComponent blendComponent; - switch (config.filterType) { - case CameraFilterType::Multiply: - blendComponent = wgpu::BlendComponent{ - .srcFactor = wgpu::BlendFactor::Zero, - .dstFactor = wgpu::BlendFactor::Src, - }; - alphaWrite = true; - break; - case CameraFilterType::Add: - blendComponent = wgpu::BlendComponent{ - .srcFactor = wgpu::BlendFactor::SrcAlpha, - .dstFactor = wgpu::BlendFactor::One, - }; - alphaWrite = false; - break; - case CameraFilterType::Subtract: - blendComponent = wgpu::BlendComponent{ - .operation = wgpu::BlendOperation::Subtract, - .srcFactor = wgpu::BlendFactor::SrcAlpha, - .dstFactor = wgpu::BlendFactor::One, - }; - alphaWrite = false; - break; - case CameraFilterType::Blend: - blendComponent = wgpu::BlendComponent{ - .srcFactor = wgpu::BlendFactor::SrcAlpha, - .dstFactor = wgpu::BlendFactor::OneMinusSrcAlpha, - }; - alphaWrite = false; - break; - case CameraFilterType::InvDstMultiply: - blendComponent = wgpu::BlendComponent{ - .srcFactor = wgpu::BlendFactor::Zero, - .dstFactor = wgpu::BlendFactor::OneMinusSrc, - }; - alphaWrite = true; - break; - default: - Log.report(logvisor::Fatal, FMT_STRING("unimplemented filter type {}"), magic_enum::enum_name(config.filterType)); - unreachable(); - } - - const auto blendState = wgpu::BlendState{ - .color = blendComponent, - .alpha = blendComponent, - }; - auto writeMask = wgpu::ColorWriteMask::Red | wgpu::ColorWriteMask::Green | wgpu::ColorWriteMask::Blue; - if (alphaWrite) { - writeMask = writeMask | wgpu::ColorWriteMask::Alpha; - } - const std::array colorTargets{ - wgpu::ColorTargetState{ - .format = g_graphicsConfig.colorFormat, - .blend = &blendState, - .writeMask = writeMask, - }, - }; - const auto fragmentState = wgpu::FragmentState{ - .module = state.shader, - .entryPoint = "fs_main", - .targetCount = colorTargets.size(), - .targets = colorTargets.data(), - }; - - const auto pipelineDescriptor = wgpu::RenderPipelineDescriptor{ - .label = "Textured Quad Pipeline", - .layout = state.pipelineLayout, - .vertex = make_vertex_state(state.shader, vertexBuffers), - .primitive = - wgpu::PrimitiveState{ - .topology = wgpu::PrimitiveTopology::TriangleStrip, - }, - .depthStencil = &depthStencil, - .multisample = - wgpu::MultisampleState{ - .count = g_graphicsConfig.msaaSamples, - }, - .fragment = &fragmentState, - }; - return g_device.CreateRenderPipeline(&pipelineDescriptor); -} - -DrawData make_draw_data(const State& state, CameraFilterType filter_type, const TextureHandle& texture, - ZComp z_comparison, bool z_test, const zeus::CColor& color, float uv_scale, - const zeus::CRectangle& rect, float z, float lod) { - auto pipeline = pipeline_ref(PipelineConfig{ - .filterType = filter_type, - .zComparison = z_comparison, - .zTest = z_test, - }); - - const std::array verts{ - Vert{{0.f, 0.f, z}, {0.0, 0.0}}, - Vert{{0.f, 1.f, z}, {0.0, uv_scale}}, - Vert{{1.f, 0.f, z}, {uv_scale, 0.0}}, - Vert{{1.f, 1.f, z}, {uv_scale, uv_scale}}, - }; - const auto vertRange = push_verts(ArrayRef{verts}); - - const auto uniform = Uniform{ - .xf = - Mat4x4{ - Vec4{rect.size.x() * 2.f, 0.f, 0.f, 0.f}, - Vec4{0.f, rect.size.y() * 2.f, 0.f, 0.f}, - Vec4{0.f, 0.f, 1.f, 0.f}, - Vec4{rect.position.x() * 2.f - 1.f, rect.position.y() * 2.f - 1.f, 0.f, 1.f}, - }, - .color = color, - .lod = lod, - }; - const auto uniformRange = push_uniform(uniform); - - const std::array entries{ - wgpu::BindGroupEntry{ - .binding = 0, - .textureView = texture.ref->view, - }, - }; - const auto textureBindGroup = bind_group_ref(wgpu::BindGroupDescriptor{ - .label = "Textured Quad Texture Bind Group", - .layout = state.textureLayout, - .entryCount = entries.size(), - .entries = entries.data(), - }); - - return { - .pipeline = pipeline, - .vertRange = vertRange, - .uniformRange = uniformRange, - .textureBindGroup = textureBindGroup, - }; -} - -DrawData make_draw_data_verts(const State& state, CameraFilterType filter_type, const TextureHandle& texture, - ZComp z_comparison, bool z_test, const zeus::CColor& color, - const ArrayRef& pos, const ArrayRef& uvs, float lod) { - auto pipeline = pipeline_ref(PipelineConfig{ - .filterType = filter_type, - .zComparison = z_comparison, - .zTest = z_test, - }); - - assert(pos.size() == 4 && uvs.size() == 4 && "Invalid pos/uv sizes!"); - - const std::array verts{ - Vert{pos[0], uvs[0]}, - Vert{pos[1], uvs[1]}, - Vert{pos[2], uvs[2]}, - Vert{pos[3], uvs[3]}, - }; - const auto vertRange = push_verts(ArrayRef{verts}); - - const auto uniform = Uniform{ - .xf = gx::get_combined_matrix(), - .color = color, - .lod = lod, - }; - const auto uniformRange = push_uniform(uniform); - - const std::array entries{ - wgpu::BindGroupEntry{ - .binding = 0, - .textureView = texture.ref->view, - }, - }; - const auto textureBindGroup = bind_group_ref(wgpu::BindGroupDescriptor{ - .label = "Textured Quad Texture Bind Group", - .layout = state.textureLayout, - .entryCount = entries.size(), - .entries = entries.data(), - }); - - return { - .pipeline = pipeline, - .vertRange = vertRange, - .uniformRange = uniformRange, - .textureBindGroup = textureBindGroup, - }; -} - -void render(const State& state, const DrawData& data, const wgpu::RenderPassEncoder& pass) { - if (!bind_pipeline(data.pipeline, pass)) { - return; - } - - const std::array offsets{data.uniformRange.offset}; - pass.SetBindGroup(0, state.uniformBindGroup, offsets.size(), offsets.data()); - pass.SetBindGroup(1, find_bind_group(data.textureBindGroup)); - pass.SetVertexBuffer(0, g_vertexBuffer, data.vertRange.offset, data.vertRange.size); - pass.Draw(4); -} -} // namespace aurora::gfx::textured_quad diff --git a/aurora/lib/gfx/textured_quad/shader.hpp b/aurora/lib/gfx/textured_quad/shader.hpp deleted file mode 100644 index 0efda3796..000000000 --- a/aurora/lib/gfx/textured_quad/shader.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include "../common.hpp" - -namespace aurora::gfx::textured_quad { -struct DrawData { - PipelineRef pipeline; - Range vertRange; - Range uniformRange; - BindGroupRef textureBindGroup; -}; - -struct PipelineConfig { - CameraFilterType filterType; - ZComp zComparison; - bool zTest; -}; -static const std::array INITIAL_PIPELINES{ - PipelineConfig{}, // TODO -}; - -struct State { - wgpu::ShaderModule shader; - wgpu::BindGroupLayout uniformLayout; - wgpu::BindGroup uniformBindGroup; - wgpu::BindGroupLayout textureLayout; - wgpu::Sampler sampler; - wgpu::PipelineLayout pipelineLayout; -}; - -struct alignas(4) Vert { - Vec3 pos; - Vec2 uv; -}; -struct alignas(4) Uniform { - Mat4x4 xf; - Vec4 color; - float lod; -}; -static_assert(sizeof(Uniform) == 84); - -State construct_state(); -wgpu::RenderPipeline create_pipeline(const State& state, [[maybe_unused]] PipelineConfig config); -DrawData make_draw_data(const State& state, CameraFilterType filter_type, const TextureHandle& texture, - ZComp z_comparison, bool z_test, const zeus::CColor& color, float uv_scale, - const zeus::CRectangle& rect, float z, float lod); -DrawData make_draw_data_verts(const State& state, CameraFilterType filter_type, const TextureHandle& texture, - ZComp z_comparison, bool z_test, const zeus::CColor& color, - const ArrayRef& pos, const ArrayRef& uvs, float lod); -void render(const State& state, const DrawData& data, const wgpu::RenderPassEncoder& pass); -} // namespace aurora::gfx::textured_quad diff --git a/aurora/lib/gpu.cpp b/aurora/lib/gpu.cpp index d6de7ac13..28b4df91a 100644 --- a/aurora/lib/gpu.cpp +++ b/aurora/lib/gpu.cpp @@ -125,7 +125,7 @@ void initialize(SDL_Window* window) { { std::vector adapters = g_Instance->GetAdapters(); - auto adapterIt = std::find_if(adapters.begin(), adapters.end(), [](const dawn::native::Adapter adapter) -> bool { + const auto adapterIt = std::find_if(adapters.begin(), adapters.end(), [](const auto& adapter) -> bool { wgpu::AdapterProperties properties; adapter.GetProperties(&properties); return properties.backendType == preferredBackendType; @@ -144,11 +144,12 @@ void initialize(SDL_Window* window) { g_AdapterProperties.driverDescription); { - WGPUSupportedLimits supportedLimits{}; + WGPUSupportedLimits supportedLimits; g_Adapter.GetLimits(&supportedLimits); const wgpu::RequiredLimits requiredLimits{ .limits = { + // Use "best" supported alignments .minUniformBufferOffsetAlignment = supportedLimits.limits.minUniformBufferOffsetAlignment, .minStorageBufferOffsetAlignment = supportedLimits.limits.minStorageBufferOffsetAlignment, },