mirror of https://github.com/AxioDL/metaforce.git
aurora: Code cleanup, more performant hashing
This commit is contained in:
parent
242dff697f
commit
4eff37fcb2
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -104,6 +104,31 @@ enum class ERglEnum : std::underlying_type_t<GX::Compare> {
|
|||
|
||||
using ERglLight = u8;
|
||||
|
||||
enum class ERglTexOffset : std::underlying_type_t<GX::TexOffset> {
|
||||
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<GX::FogType> {
|
||||
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 <class VTX>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<zeus::CMatrix4f, 6> m_texMtxs;
|
||||
std::array<Ripple, 20> m_ripple;
|
||||
zeus::CVector4f m_colorMul;
|
||||
std::array<zeus::CVector4f, 3> 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<zeus::CMatrix4f, 6> m_texMtxs;
|
||||
// std::array<Ripple, 20> m_ripple;
|
||||
// zeus::CVector4f m_colorMul;
|
||||
// std::array<zeus::CVector4f, 3> 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<CTexture> m_patternTex1;
|
||||
TLockedToken<CTexture> m_patternTex2;
|
||||
|
|
|
@ -10,54 +10,54 @@ namespace metaforce {
|
|||
|
||||
//std::unordered_map<uint64_t, CModelShaders::ShaderPipelines> CModelShaders::g_ShaderPipelines;
|
||||
|
||||
void CModelShaders::LightingUniform::ActivateLights(const std::vector<CLight>& 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<CLight>& 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;
|
||||
//
|
||||
|
|
|
@ -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<float, 4> linAtt{1.f, 0.f, 0.f};
|
||||
std::array<float, 4> angAtt{1.f, 0.f, 0.f};
|
||||
};
|
||||
|
||||
struct LightingUniform {
|
||||
std::array<Light, URDE_MAX_LIGHTS> lights;
|
||||
zeus::CColor ambient;
|
||||
std::array<zeus::CColor, 3> colorRegs;
|
||||
zeus::CColor mulColor;
|
||||
zeus::CColor addColor;
|
||||
CFogState fog;
|
||||
|
||||
void ActivateLights(const std::vector<CLight>& 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<float, 4> linAtt{1.f, 0.f, 0.f};
|
||||
// std::array<float, 4> angAtt{1.f, 0.f, 0.f};
|
||||
// };
|
||||
//
|
||||
// struct LightingUniform {
|
||||
// std::array<Light, URDE_MAX_LIGHTS> lights;
|
||||
// zeus::CColor ambient;
|
||||
// std::array<zeus::CColor, 3> colorRegs;
|
||||
// zeus::CColor mulColor;
|
||||
// zeus::CColor addColor;
|
||||
// CFogState fog;
|
||||
//
|
||||
// void ActivateLights(const std::vector<CLight>& 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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -18,22 +18,6 @@
|
|||
#include <zeus/CVector4f.hpp>
|
||||
|
||||
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<zeus::CVector4f>& 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<zeus::CVector3f>& pos,
|
||||
const ArrayRef<zeus::CVector2f>& 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<zeus::CVector3f>& 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;
|
||||
|
||||
|
|
|
@ -242,7 +242,7 @@ void app_run(std::unique_ptr<AppDelegate> 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 {
|
||||
|
|
|
@ -1,310 +0,0 @@
|
|||
#include "shader.hpp"
|
||||
|
||||
#include "../../gpu.hpp"
|
||||
#include "../gx.hpp"
|
||||
|
||||
#include <logvisor/logvisor.hpp>
|
||||
#include <magic_enum.hpp>
|
||||
|
||||
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<f32>;
|
||||
color: vec4<f32>;
|
||||
};
|
||||
@group(0) @binding(0)
|
||||
var<uniform> ubuf: Uniform;
|
||||
|
||||
struct VertexOutput {
|
||||
@builtin(position) pos: vec4<f32>;
|
||||
//@builtin(normal) norm: vec4<f32>;
|
||||
};
|
||||
|
||||
@stage(vertex)
|
||||
fn vs_main(@location(0) in_pos: vec3<f32>) -> VertexOutput {//, @location(1) in_norm: vec3<f32>) -> VertexOutput {
|
||||
var out: VertexOutput;
|
||||
out.pos = ubuf.xf * vec4<f32>(in_pos, 1.0);
|
||||
//out.norm = in_norm;
|
||||
return out;
|
||||
}
|
||||
|
||||
@stage(fragment)
|
||||
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
|
||||
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<float>{
|
||||
Vec4<float>{rect.size.x() * 2.f, 0.f, 0.f, 0.f},
|
||||
Vec4<float>{0.f, rect.size.y() * 2.f, 0.f, 0.f},
|
||||
Vec4<float>{0.f, 0.f, 1.f, 0.f},
|
||||
Vec4<float>{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<zeus::CVector3f>& 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
|
|
@ -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<float> pos;
|
||||
};
|
||||
|
||||
struct alignas(4) Uniform {
|
||||
Mat4x4<float> xf;
|
||||
Vec4<float> 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<zeus::CVector3f>& pos);
|
||||
|
||||
void render(const State& state, const DrawData& data, const wgpu::RenderPassEncoder& pass);
|
||||
} // namespace aurora::gfx::colored_quad
|
|
@ -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 <absl/container/flat_hash_map.h>
|
||||
#include <condition_variable>
|
||||
#include <deque>
|
||||
#include <logvisor/logvisor.hpp>
|
||||
#include <thread>
|
||||
#include <absl/container/flat_hash_map.h>
|
||||
|
||||
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<const u8*>(&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<gfx::gx::PipelineConfig>(state, input);
|
||||
}
|
||||
template <>
|
||||
inline void xxh3_update(XXH3_state_t& state, const gfx::model::PipelineConfig& input) {
|
||||
xxh3_update<gfx::gx::PipelineConfig>(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<const u8*>(&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<wgpu::Buffer, 3> g_stagingBuffers;
|
||||
static wgpu::SupportedLimits g_cachedLimits;
|
||||
|
||||
static ShaderState g_state;
|
||||
static PipelineRef g_currentPipeline;
|
||||
|
||||
static std::vector<Command> 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<zeus::CVector4f>& 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<zeus::CVector3f>& pos,
|
||||
const ArrayRef<zeus::CVector2f>& 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<zeus::CVector3f>& 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<XXH64_hash_t>(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<XXH64_hash_t>(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<XXH64_hash_t>(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<ByteBuffer, Range> map_indices(size_t length) {
|
|||
return {ByteBuffer{g_indices.data() + range.offset, range.size}, range};
|
||||
}
|
||||
std::pair<ByteBuffer, Range> 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<ByteBuffer, Range> 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
#include <aurora/gfx.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include <dawn/webgpu_cpp.h>
|
||||
|
@ -11,18 +12,15 @@
|
|||
#endif
|
||||
|
||||
namespace aurora {
|
||||
template <typename T>
|
||||
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 <typename T>
|
||||
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<T>);
|
||||
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,
|
||||
|
|
|
@ -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<float> 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 {
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "common.hpp"
|
||||
|
||||
#include <type_traits>
|
||||
#include <variant>
|
||||
|
||||
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<TevPass<GX::TevColorArg, GX::CC_ZERO>>);
|
||||
static_assert(std::has_unique_object_representations_v<TevPass<GX::TevAlphaArg, GX::CA_ZERO>>);
|
||||
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<TevOp>);
|
||||
struct TevStage {
|
||||
TevPass<GX::TevColorArg, GX::CC_ZERO> colorPass;
|
||||
TevPass<GX::TevAlphaArg, GX::CA_ZERO> 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<TevStage>);
|
||||
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<ColorChannelConfig>);
|
||||
// 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<TcgConfig>);
|
||||
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<TevSwap>);
|
||||
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<AlphaCompare>);
|
||||
|
||||
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<float> dstAlpha;
|
||||
u32 dstAlpha; // u8; UINT32_MAX = disabled
|
||||
AlphaCompare alphaCompare;
|
||||
std::array<zeus::CColor, MaxTevRegs> colorRegs;
|
||||
std::array<zeus::CColor, GX::MAX_KCOLOR> kcolors;
|
||||
|
@ -158,13 +170,15 @@ struct ShaderConfig {
|
|||
GX::FogType fogType;
|
||||
std::array<GX::AttrType, MaxVtxAttr> vtxAttrs;
|
||||
std::array<TevSwap, MaxTevSwap> tevSwapTable;
|
||||
std::array<std::optional<TevStage>, MaxTevStages> tevStages;
|
||||
std::array<TevStage, MaxTevStages> tevStages;
|
||||
u32 tevStageCount = 0;
|
||||
std::array<ColorChannelConfig, MaxColorChannels> colorChannels;
|
||||
std::array<TcgConfig, MaxTexCoord> tcgs;
|
||||
AlphaCompare alphaCompare;
|
||||
u32 indexedAttributeCount = 0;
|
||||
bool operator==(const ShaderConfig&) const = default;
|
||||
};
|
||||
static_assert(std::has_unique_object_representations_v<ShaderConfig>);
|
||||
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<float> dstAlpha;
|
||||
u32 dstAlpha;
|
||||
bool depthCompare, depthUpdate, alphaUpdate;
|
||||
u8 _pad;
|
||||
};
|
||||
static_assert(std::has_unique_object_representations_v<PipelineConfig>);
|
||||
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<MaxTextures> sampledTextures;
|
||||
std::bitset<MaxKColors> sampledKColors;
|
||||
std::bitset<MaxColorChannels> 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<wgpu::VertexBufferLayout> vtxBuffers, wgpu::ShaderModule shader,
|
||||
zstring_view label) noexcept;
|
||||
std::pair<wgpu::ShaderModule, ShaderInfo> 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 <typename Arg, Arg Default>
|
||||
inline void xxh3_update(XXH3_state_t& state, const gfx::gx::TevPass<Arg, Default>& 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
|
||||
|
|
|
@ -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<std::string_view, MaxVtxAttr> VtxAttributeNames{
|
|||
"pos_mtx_array", "nrm_mtx_array", "tex_mtx_array", "light_array", "nbt",
|
||||
};
|
||||
|
||||
std::pair<wgpu::ShaderModule, ShaderInfo> 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<wgpu::ShaderModule, ShaderInfo> 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<wgpu::ShaderModule, ShaderInfo> 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<f32>({}), vec3<f32>(0.0), vec3<f32>(1.0))"), op);
|
||||
}
|
||||
fragmentFn += fmt::format(FMT_STRING("\n {0} = vec4<f32>({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<f32>;"), i);
|
||||
fragmentFnPre += fmt::format(FMT_STRING("\n var tevreg{0} = ubuf.tevreg{0};"), i);
|
||||
}
|
||||
uniBufAttrs += fmt::format(FMT_STRING("\n tevreg{}: vec4<f32>;"), 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<wgpu::ShaderModule, ShaderInfo> build_shader(const ShaderConfig& confi
|
|||
|
||||
uniBufAttrs += fmt::format(FMT_STRING("\n cc{0}_amb: vec4<f32>;"), i);
|
||||
uniBufAttrs += fmt::format(FMT_STRING("\n cc{0}_mat: vec4<f32>;"), i);
|
||||
info.uniformSize += 32;
|
||||
|
||||
if (config.colorChannels[i].lightingEnabled) {
|
||||
if (!addedLightStruct) {
|
||||
|
@ -700,7 +840,6 @@ std::pair<wgpu::ShaderModule, ShaderInfo> build_shader(const ShaderConfig& confi
|
|||
|
||||
uniBufAttrs += fmt::format(FMT_STRING("\n lights{}: array<Light, {}>;"), i, GX::MaxLights);
|
||||
uniBufAttrs += fmt::format(FMT_STRING("\n lighting_ambient{}: vec4<f32>;"), i);
|
||||
info.uniformSize += (80 * GX::MaxLights) + 16;
|
||||
|
||||
vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) cc{}: vec4<f32>;"), vtxOutIdx++, i);
|
||||
vtxXfrAttrs += fmt::format(FMT_STRING(R"""(
|
||||
|
@ -734,11 +873,9 @@ std::pair<wgpu::ShaderModule, ShaderInfo> 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<f32>;"), i);
|
||||
}
|
||||
uniBufAttrs += fmt::format(FMT_STRING("\n kcolor{}: vec4<f32>;"), i);
|
||||
info.uniformSize += 16;
|
||||
}
|
||||
size_t texBindIdx = 0;
|
||||
for (int i = 0; i < info.sampledTextures.size(); ++i) {
|
||||
|
@ -763,8 +900,6 @@ std::pair<wgpu::ShaderModule, ShaderInfo> 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<wgpu::ShaderModule, ShaderInfo> 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<f32>(tc{0}_tmp.xyz, 1.0);"),
|
||||
i, postMtxIdx);
|
||||
}
|
||||
|
@ -783,33 +917,26 @@ std::pair<wgpu::ShaderModule, ShaderInfo> 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<f32>;"), i);
|
||||
info.uniformSize += 32;
|
||||
break;
|
||||
case GX::TG_MTX3x4:
|
||||
uniBufAttrs += fmt::format(FMT_STRING("\n texmtx{}: mat4x3<f32>;"), 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<f32>;"), i);
|
||||
break;
|
||||
case GX::TG_MTX3x4:
|
||||
uniBufAttrs += fmt::format(FMT_STRING("\n texmtx{}: mat4x3<f32>;"), 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<f32>;"), i);
|
||||
}
|
||||
uniBufAttrs += fmt::format(FMT_STRING("\n postmtx{}: mat4x3<f32>;"), 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<wgpu::ShaderModule, ShaderInfo> 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<wgpu::ShaderModule, ShaderInfo> 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<f32> {{
|
|||
};
|
||||
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
|
||||
|
|
|
@ -40,7 +40,7 @@ static inline void read_vert(ByteBuffer& out, const u8* data) noexcept {
|
|||
static absl::flat_hash_map<XXH64_hash_t, std::pair<ByteBuffer, ByteBuffer>> 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<wgpu::VertexAttribute, gx::MaxVtxAttr> vtxAttrs;
|
||||
std::array<wgpu::VertexAttribute, gx::MaxVtxAttr> 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);
|
||||
|
|
|
@ -12,7 +12,7 @@ struct DrawData {
|
|||
Range uniformRange;
|
||||
uint32_t indexCount;
|
||||
gx::GXBindGroups bindGroups;
|
||||
std::optional<float> dstAlpha;
|
||||
u32 dstAlpha;
|
||||
};
|
||||
|
||||
struct PipelineConfig : gx::PipelineConfig {};
|
||||
|
|
|
@ -11,8 +11,9 @@ struct DrawData {
|
|||
};
|
||||
|
||||
struct PipelineConfig {
|
||||
// nothing
|
||||
u32 pad = 0; // empty
|
||||
};
|
||||
static_assert(std::has_unique_object_representations_v<PipelineConfig>);
|
||||
static const std::array INITIAL_PIPELINES{
|
||||
PipelineConfig{},
|
||||
};
|
||||
|
|
|
@ -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<uint32_t>(sStreamState->indices.size()),
|
||||
.bindGroups = info.bindGroups,
|
||||
.bindGroups = aurora::gfx::gx::build_bind_groups(info, config.shaderConfig, {}),
|
||||
.dstAlpha = g_gxState.dstAlpha,
|
||||
});
|
||||
sStreamState.reset();
|
||||
|
|
|
@ -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<wgpu::VertexAttribute, 4> 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);
|
||||
|
|
|
@ -11,7 +11,7 @@ struct DrawData {
|
|||
Range indexRange;
|
||||
uint32_t indexCount;
|
||||
gx::GXBindGroups bindGroups;
|
||||
std::optional<float> dstAlpha;
|
||||
u32 dstAlpha;
|
||||
};
|
||||
|
||||
struct PipelineConfig : public gx::PipelineConfig {};
|
||||
|
|
|
@ -1,389 +0,0 @@
|
|||
#include "shader.hpp"
|
||||
|
||||
#include "../gx.hpp"
|
||||
#include "../../gpu.hpp"
|
||||
|
||||
#include <logvisor/logvisor.hpp>
|
||||
#include <magic_enum.hpp>
|
||||
|
||||
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<f32>;
|
||||
color: vec4<f32>;
|
||||
lod: f32;
|
||||
};
|
||||
@group(0) @binding(0)
|
||||
var<uniform> ubuf: Uniform;
|
||||
@group(0) @binding(1)
|
||||
var texture_sampler: sampler;
|
||||
@group(1) @binding(0)
|
||||
var texture: texture_2d<f32>;
|
||||
|
||||
struct VertexOutput {
|
||||
@builtin(position) pos: vec4<f32>;
|
||||
@location(0) uv: vec2<f32>;
|
||||
};
|
||||
|
||||
@stage(vertex)
|
||||
fn vs_main(@location(0) in_pos: vec3<f32>, @location(1) in_uv: vec2<f32>) -> VertexOutput {
|
||||
var out: VertexOutput;
|
||||
out.pos = ubuf.xf * vec4<f32>(in_pos, 1.0);
|
||||
out.uv = in_uv;
|
||||
return out;
|
||||
}
|
||||
|
||||
@stage(fragment)
|
||||
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
|
||||
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<float>{
|
||||
Vec4<float>{rect.size.x() * 2.f, 0.f, 0.f, 0.f},
|
||||
Vec4<float>{0.f, rect.size.y() * 2.f, 0.f, 0.f},
|
||||
Vec4<float>{0.f, 0.f, 1.f, 0.f},
|
||||
Vec4<float>{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<zeus::CVector3f>& pos, const ArrayRef<zeus::CVector2f>& 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
|
|
@ -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<float> pos;
|
||||
Vec2<float> uv;
|
||||
};
|
||||
struct alignas(4) Uniform {
|
||||
Mat4x4<float> xf;
|
||||
Vec4<float> 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<zeus::CVector3f>& pos, const ArrayRef<zeus::CVector2f>& uvs, float lod);
|
||||
void render(const State& state, const DrawData& data, const wgpu::RenderPassEncoder& pass);
|
||||
} // namespace aurora::gfx::textured_quad
|
|
@ -125,7 +125,7 @@ void initialize(SDL_Window* window) {
|
|||
|
||||
{
|
||||
std::vector<dawn::native::Adapter> 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,
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue