aurora: Code cleanup, more performant hashing

This commit is contained in:
Luke Street 2022-05-02 19:42:59 -04:00
parent 242dff697f
commit 4eff37fcb2
27 changed files with 531 additions and 1509 deletions

View File

@ -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);
}
}

View File

@ -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>

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;
//

View File

@ -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();

View File

@ -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);
}
}

View File

@ -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
)

View File

@ -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;

View File

@ -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 {

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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,

View File

@ -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 {

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -12,7 +12,7 @@ struct DrawData {
Range uniformRange;
uint32_t indexCount;
gx::GXBindGroups bindGroups;
std::optional<float> dstAlpha;
u32 dstAlpha;
};
struct PipelineConfig : gx::PipelineConfig {};

View File

@ -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{},
};

View File

@ -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();

View File

@ -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);

View File

@ -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 {};

View File

@ -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

View File

@ -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

View File

@ -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,
},