mirror of https://github.com/AxioDL/metaforce.git
aurora: Working palette textures
This commit is contained in:
parent
ef771e6489
commit
ef71c009c6
|
@ -748,10 +748,11 @@ enum GXTlutFmt {
|
|||
GX_MAX_TLUTFMT = 0x3,
|
||||
};
|
||||
|
||||
namespace aurora::gfx {
|
||||
struct TextureRef;
|
||||
} // namespace aurora::gfx
|
||||
struct GXTlutObj {
|
||||
u32 format;
|
||||
u32 addr;
|
||||
u16 entries;
|
||||
std::shared_ptr<aurora::gfx::TextureRef> ref;
|
||||
};
|
||||
|
||||
enum GXTlut {
|
||||
|
@ -806,12 +807,9 @@ enum GXCITexFmt {
|
|||
GX_TF_C14X2 = GX::TF_C14X2,
|
||||
};
|
||||
|
||||
namespace aurora::gfx {
|
||||
struct TextureRef;
|
||||
} // namespace aurora::gfx
|
||||
struct GXTexObj {
|
||||
std::shared_ptr<aurora::gfx::TextureRef> ref;
|
||||
void* data;
|
||||
const void* data;
|
||||
u32 dataSize;
|
||||
u16 width;
|
||||
u16 height;
|
||||
|
@ -894,12 +892,13 @@ void GXSetTevSwapModeTable(GX::TevSwapSel id, GX::TevColorChan red, GX::TevColor
|
|||
GX::TevColorChan alpha) noexcept;
|
||||
void GXSetTevSwapMode(GX::TevStageID stage, GX::TevSwapSel rasSel, GX::TevSwapSel texSel) noexcept;
|
||||
void GXSetLineWidth(u8 width, GX::TexOffset texOffset) noexcept;
|
||||
void GXInitTlutObj(GXTlutObj* obj, void* data, GXTlutFmt format, u16 entries) noexcept;
|
||||
void GXInitTlutObj(GXTlutObj* obj, const void* data, GXTlutFmt format, u16 entries) noexcept;
|
||||
void GXLoadTlut(const GXTlutObj* obj, GXTlut idx) noexcept;
|
||||
void GXInitTexObj(GXTexObj* obj, void* data, u16 width, u16 height, GX::TextureFormat format, GXTexWrapMode wrapS,
|
||||
void GXInitTexObj(GXTexObj* obj, const void* data, u16 width, u16 height, GX::TextureFormat format, GXTexWrapMode wrapS,
|
||||
GXTexWrapMode wrapT, GXBool mipmap) noexcept;
|
||||
// Addition for binding render textures
|
||||
void GXInitTexObjResolved(GXTexObj* obj, u32 bindIdx, GX::TextureFormat format, GXTexWrapMode wrapS, GXTexWrapMode wrapT);
|
||||
void GXInitTexObjResolved(GXTexObj* obj, u32 bindIdx, GX::TextureFormat format, GXTexWrapMode wrapS,
|
||||
GXTexWrapMode wrapT);
|
||||
void GXInitTexObjLOD(GXTexObj* obj, GXTexFilter minFilt, GXTexFilter magFilt, float minLod, float maxLod, float lodBias,
|
||||
GXBool biasClamp, GXBool doEdgeLod, GXAnisotropy maxAniso) noexcept;
|
||||
void GXInitTexObjCI(GXTexObj* obj, void* data, u16 width, u16 height, GXCITexFmt format, GXTexWrapMode wrapS,
|
||||
|
|
|
@ -155,10 +155,10 @@ void CRasterFont::DrawString(const CDrawStringOptions& opts, int x, int y, int&
|
|||
if (renderBuf != nullptr) {
|
||||
CGraphicsPalette pal(EPaletteFormat::RGB5A3, 4);
|
||||
pal.Lock();
|
||||
*reinterpret_cast<u16*>(pal.GetPaletteData() + 0) = SBIG(zeus::CColor(0.f, 0.f, 0.f, 0.f).toRGB5A3());
|
||||
*reinterpret_cast<u16*>(pal.GetPaletteData() + 2) = SBIG(opts.x4_colors[0].toRGB5A3());
|
||||
*reinterpret_cast<u16*>(pal.GetPaletteData() + 4) = SBIG(opts.x4_colors[1].toRGB5A3());
|
||||
*reinterpret_cast<u16*>(pal.GetPaletteData() + 6) = SBIG(zeus::CColor(0.f, 0.f, 0.f, 0.f).toRGB5A3());
|
||||
*reinterpret_cast<u16*>(pal.GetPaletteData() + 0) = bswap16(zeus::CColor(0.f, 0.f, 0.f, 0.f).toRGB5A3());
|
||||
*reinterpret_cast<u16*>(pal.GetPaletteData() + 2) = bswap16(opts.x4_colors[0].toRGB5A3());
|
||||
*reinterpret_cast<u16*>(pal.GetPaletteData() + 4) = bswap16(opts.x4_colors[1].toRGB5A3());
|
||||
*reinterpret_cast<u16*>(pal.GetPaletteData() + 6) = bswap16(zeus::CColor(0.f, 0.f, 0.f, 0.f).toRGB5A3());
|
||||
pal.UnLock();
|
||||
renderBuf->AddPaletteChange(pal);
|
||||
}
|
||||
|
|
|
@ -102,11 +102,6 @@ u32 CTextRenderBuffer::GetCurLen() {
|
|||
}
|
||||
|
||||
void CTextRenderBuffer::Render(const zeus::CColor& color, float time) {
|
||||
static const GX::VtxDescList skVtxDesc[3]{
|
||||
{GX::VA_POS, GX::DIRECT},
|
||||
{GX::VA_TEX0, GX::DIRECT},
|
||||
{GX::VA_NULL, GX::NONE},
|
||||
};
|
||||
x4c_activeFont = -1;
|
||||
x4d_activePalette = -1;
|
||||
CMemoryInStream in(x34_bytecode.data(), x44_blobSize);
|
||||
|
@ -127,8 +122,8 @@ void CTextRenderBuffer::Render(const zeus::CColor& color, float time) {
|
|||
x4f_queuedPalette = -1;
|
||||
}
|
||||
|
||||
u16 offX = in.ReadShort();
|
||||
u16 offY = in.ReadShort();
|
||||
s16 offX = in.ReadShort();
|
||||
s16 offY = in.ReadShort();
|
||||
char16_t chr = in.ReadShort();
|
||||
zeus::CColor chrColor(static_cast<zeus::Comp32>(in.ReadLong()));
|
||||
if (x4c_activeFont != -1) {
|
||||
|
@ -151,8 +146,8 @@ void CTextRenderBuffer::Render(const zeus::CColor& color, float time) {
|
|||
}
|
||||
}
|
||||
} else if (cmd == Command::ImageRender) {
|
||||
u16 offX = in.ReadShort();
|
||||
u16 offY = in.ReadShort();
|
||||
s16 offX = in.ReadShort();
|
||||
s16 offY = in.ReadShort();
|
||||
u8 imageIdx = in.ReadChar();
|
||||
zeus::CColor imageColor(static_cast<zeus::Comp32>(in.ReadLong()));
|
||||
auto imageDef = x14_images[imageIdx];
|
||||
|
@ -169,7 +164,12 @@ void CTextRenderBuffer::Render(const zeus::CColor& color, float time) {
|
|||
CGX::SetTevColorIn(GX::TEVSTAGE0, GX::CC_ZERO, GX::CC_TEXC, GX::CC_KONST, GX::CC_ZERO);
|
||||
CGX::SetTevAlphaIn(GX::TEVSTAGE0, GX::CA_ZERO, GX::CA_TEXA, GX::CA_KONST, GX::CA_ZERO);
|
||||
CGX::SetStandardTevColorAlphaOp(GX::TEVSTAGE0);
|
||||
CGX::SetVtxDescv(skVtxDesc);
|
||||
constexpr std::array skVtxDesc{
|
||||
GX::VtxDescList{GX::VA_POS, GX::DIRECT},
|
||||
GX::VtxDescList{GX::VA_TEX0, GX::DIRECT},
|
||||
GX::VtxDescList{},
|
||||
};
|
||||
CGX::SetVtxDescv(skVtxDesc.data());
|
||||
CGX::SetNumChans(0);
|
||||
CGX::SetNumTexGens(1);
|
||||
CGX::SetNumTevStages(1);
|
||||
|
|
|
@ -493,7 +493,7 @@ void GXSetIndTexMtx(GX::IndTexMtxID id, const void* mtx, s8 scaleExp) noexcept {
|
|||
g_gxState.indTexMtxs[id - 1] = {*static_cast<const aurora::Mat3x2<float>*>(mtx), scaleExp};
|
||||
}
|
||||
|
||||
void GXInitTexObj(GXTexObj* obj, void* data, u16 width, u16 height, GX::TextureFormat format, GXTexWrapMode wrapS,
|
||||
void GXInitTexObj(GXTexObj* obj, const void* data, u16 width, u16 height, GX::TextureFormat format, GXTexWrapMode wrapS,
|
||||
GXTexWrapMode wrapT, GXBool mipmap) noexcept {
|
||||
obj->data = data;
|
||||
obj->width = width;
|
||||
|
@ -550,7 +550,24 @@ void GXInitTexObjLOD(GXTexObj* obj, GXTexFilter minFilt, GXTexFilter magFilt, fl
|
|||
}
|
||||
void GXInitTexObjCI(GXTexObj* obj, void* data, u16 width, u16 height, GXCITexFmt format, GXTexWrapMode wrapS,
|
||||
GXTexWrapMode wrapT, GXBool mipmap, u32 tlut) noexcept {
|
||||
// TODO
|
||||
obj->data = data;
|
||||
obj->width = width;
|
||||
obj->height = height;
|
||||
obj->fmt = static_cast<GX::TextureFormat>(format);
|
||||
obj->wrapS = wrapS;
|
||||
obj->wrapT = wrapT;
|
||||
obj->hasMips = mipmap;
|
||||
obj->tlut = static_cast<GXTlut>(tlut);
|
||||
// TODO default values?
|
||||
obj->minFilter = GX_LINEAR;
|
||||
obj->magFilter = GX_LINEAR;
|
||||
obj->minLod = 0.f;
|
||||
obj->maxLod = 0.f;
|
||||
obj->lodBias = 0.f;
|
||||
obj->biasClamp = false;
|
||||
obj->doEdgeLod = false;
|
||||
obj->maxAniso = GX_ANISO_4;
|
||||
obj->dataInvalidated = true;
|
||||
}
|
||||
void GXInitTexObjData(GXTexObj* obj, void* data) noexcept {
|
||||
obj->data = data;
|
||||
|
@ -573,12 +590,27 @@ void GXLoadTexObj(GXTexObj* obj, GX::TexMapID id) noexcept {
|
|||
g_gxState.textures[id] = {*obj};
|
||||
}
|
||||
|
||||
void GXInitTlutObj(GXTlutObj* obj, void* data, GXTlutFmt format, u16 entries) noexcept {
|
||||
// TODO
|
||||
}
|
||||
void GXLoadTlut(const GXTlutObj* obj, GXTlut idx) noexcept {
|
||||
// TODO
|
||||
void GXInitTlutObj(GXTlutObj* obj, const void* data, GXTlutFmt format, u16 entries) noexcept {
|
||||
GX::TextureFormat texFmt;
|
||||
switch (format) {
|
||||
case GX_TL_IA8:
|
||||
texFmt = GX::TF_IA8;
|
||||
break;
|
||||
case GX_TL_RGB565:
|
||||
texFmt = GX::TF_RGB565;
|
||||
break;
|
||||
case GX_TL_RGB5A3:
|
||||
texFmt = GX::TF_RGB5A3;
|
||||
break;
|
||||
default:
|
||||
Log.report(logvisor::Fatal, FMT_STRING("invalid tlut format {}"), format);
|
||||
unreachable();
|
||||
}
|
||||
obj->ref = aurora::gfx::new_static_texture_2d(
|
||||
entries, 1, 1, texFmt, aurora::ArrayRef{static_cast<const u8*>(data), static_cast<size_t>(entries) * 2},
|
||||
"GXInitTlutObj");
|
||||
}
|
||||
void GXLoadTlut(const GXTlutObj* obj, GXTlut idx) noexcept { g_gxState.tluts[idx] = *obj; }
|
||||
|
||||
namespace aurora::gfx {
|
||||
static logvisor::Module Log("aurora::gfx::gx");
|
||||
|
@ -869,7 +901,7 @@ void populate_pipeline_config(PipelineConfig& config, GX::Primitive primitive) n
|
|||
} else {
|
||||
// Loaded texture object, no conversion necessary
|
||||
copyFmt = InvalidTextureFormat;
|
||||
bindFmt = InvalidTextureFormat;
|
||||
bindFmt = bind.texObj.fmt;
|
||||
}
|
||||
config.shaderConfig.textureConfig[i] = {copyFmt, bindFmt, flipUV};
|
||||
}
|
||||
|
@ -1005,7 +1037,6 @@ static absl::flat_hash_map<u32, std::pair<wgpu::BindGroupLayout, wgpu::BindGroup
|
|||
GXBindGroups build_bind_groups(const ShaderInfo& info, const ShaderConfig& config,
|
||||
const BindGroupRanges& ranges) noexcept {
|
||||
const auto layouts = build_bind_group_layouts(info, config);
|
||||
u32 textureCount = info.sampledTextures.count();
|
||||
|
||||
const std::array uniformEntries{
|
||||
wgpu::BindGroupEntry{
|
||||
|
@ -1039,7 +1070,9 @@ GXBindGroups build_bind_groups(const ShaderInfo& info, const ShaderConfig& confi
|
|||
},
|
||||
};
|
||||
std::array<wgpu::BindGroupEntry, MaxTextures> samplerEntries;
|
||||
std::array<wgpu::BindGroupEntry, MaxTextures> textureEntries;
|
||||
std::array<wgpu::BindGroupEntry, MaxTextures * 2> textureEntries;
|
||||
u32 samplerCount = 0;
|
||||
u32 textureCount = 0;
|
||||
for (u32 texIdx = 0, i = 0; texIdx < info.sampledTextures.size(); ++texIdx) {
|
||||
if (!info.sampledTextures.test(texIdx)) {
|
||||
continue;
|
||||
|
@ -1053,10 +1086,31 @@ GXBindGroups build_bind_groups(const ShaderInfo& info, const ShaderConfig& confi
|
|||
.binding = i,
|
||||
.sampler = sampler_ref(tex.get_descriptor()),
|
||||
};
|
||||
++samplerCount;
|
||||
textureEntries[i] = {
|
||||
.binding = i,
|
||||
.textureView = tex.texObj.ref->view,
|
||||
};
|
||||
// Load palette
|
||||
const auto& texConfig = config.textureConfig[i];
|
||||
if (texConfig.loadFmt == GX::TF_C4 || texConfig.loadFmt == GX::TF_C8 || texConfig.loadFmt == GX::TF_C14X2) {
|
||||
++i;
|
||||
u32 tlut = tex.texObj.tlut;
|
||||
if (tlut < GX_TLUT0 || tlut > GX_TLUT7) {
|
||||
Log.report(logvisor::Fatal, FMT_STRING("tlut out of bounds {}"), tlut);
|
||||
unreachable();
|
||||
} else if (!g_gxState.tluts[tlut].ref) {
|
||||
Log.report(logvisor::Fatal, FMT_STRING("tlut unbound {}"), tlut);
|
||||
unreachable();
|
||||
}
|
||||
textureEntries[i] = {
|
||||
.binding = i,
|
||||
.textureView = g_gxState.tluts[tlut].ref->view,
|
||||
};
|
||||
textureCount += 2;
|
||||
} else {
|
||||
++textureCount;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return {
|
||||
|
@ -1069,7 +1123,7 @@ GXBindGroups build_bind_groups(const ShaderInfo& info, const ShaderConfig& confi
|
|||
.samplerBindGroup = bind_group_ref(wgpu::BindGroupDescriptor{
|
||||
.label = "GX Sampler Bind Group",
|
||||
.layout = layouts.samplerLayout,
|
||||
.entryCount = textureCount,
|
||||
.entryCount = samplerCount,
|
||||
.entries = samplerEntries.data(),
|
||||
}),
|
||||
.textureBindGroup = bind_group_ref(wgpu::BindGroupDescriptor{
|
||||
|
@ -1146,22 +1200,37 @@ GXBindGroupLayouts build_bind_group_layouts(const ShaderInfo& info, const Shader
|
|||
}
|
||||
|
||||
u32 textureCount = info.sampledTextures.count();
|
||||
const auto textureIt = sTextureBindGroupLayouts.find(textureCount);
|
||||
if (textureIt != sTextureBindGroupLayouts.end()) {
|
||||
const auto& [sl, tl] = textureIt->second;
|
||||
out.samplerLayout = sl;
|
||||
out.textureLayout = tl;
|
||||
} else {
|
||||
// const auto textureIt = sTextureBindGroupLayouts.find(textureCount);
|
||||
// if (textureIt != sTextureBindGroupLayouts.end()) {
|
||||
// const auto& [sl, tl] = textureIt->second;
|
||||
// out.samplerLayout = sl;
|
||||
// out.textureLayout = tl;
|
||||
// } else {
|
||||
u32 numSamplers = 0;
|
||||
u32 numTextures = 0;
|
||||
std::array<wgpu::BindGroupLayoutEntry, MaxTextures> samplerEntries;
|
||||
std::array<wgpu::BindGroupLayoutEntry, MaxTextures> textureEntries;
|
||||
for (u32 i = 0; i < textureCount; ++i) {
|
||||
std::array<wgpu::BindGroupLayoutEntry, MaxTextures * 2> textureEntries;
|
||||
for (u32 i = 0, t = 0; i < textureCount; ++i, ++t) {
|
||||
samplerEntries[i] = {
|
||||
.binding = i,
|
||||
.visibility = wgpu::ShaderStage::Fragment,
|
||||
.sampler = {.type = wgpu::SamplerBindingType::Filtering},
|
||||
};
|
||||
textureEntries[i] = {
|
||||
.binding = i,
|
||||
++numSamplers;
|
||||
const auto& texConfig = config.textureConfig[i];
|
||||
if (texConfig.loadFmt == GX::TF_C4 || texConfig.loadFmt == GX::TF_C8 || texConfig.loadFmt == GX::TF_C14X2) {
|
||||
textureEntries[t] = {
|
||||
.binding = t,
|
||||
.visibility = wgpu::ShaderStage::Fragment,
|
||||
.texture =
|
||||
{
|
||||
.sampleType = wgpu::TextureSampleType::Sint,
|
||||
.viewDimension = wgpu::TextureViewDimension::e2D,
|
||||
},
|
||||
};
|
||||
++t;
|
||||
textureEntries[t] = {
|
||||
.binding = t,
|
||||
.visibility = wgpu::ShaderStage::Fragment,
|
||||
.texture =
|
||||
{
|
||||
|
@ -1169,11 +1238,24 @@ GXBindGroupLayouts build_bind_group_layouts(const ShaderInfo& info, const Shader
|
|||
.viewDimension = wgpu::TextureViewDimension::e2D,
|
||||
},
|
||||
};
|
||||
numTextures += 2;
|
||||
} else {
|
||||
textureEntries[t] = {
|
||||
.binding = t,
|
||||
.visibility = wgpu::ShaderStage::Fragment,
|
||||
.texture =
|
||||
{
|
||||
.sampleType = wgpu::TextureSampleType::Float,
|
||||
.viewDimension = wgpu::TextureViewDimension::e2D,
|
||||
},
|
||||
};
|
||||
++numTextures;
|
||||
}
|
||||
}
|
||||
{
|
||||
const wgpu::BindGroupLayoutDescriptor descriptor{
|
||||
.label = "GX Sampler Bind Group",
|
||||
.entryCount = textureCount,
|
||||
.entryCount = numSamplers,
|
||||
.entries = samplerEntries.data(),
|
||||
};
|
||||
out.samplerLayout = g_device.CreateBindGroupLayout(&descriptor);
|
||||
|
@ -1181,13 +1263,13 @@ GXBindGroupLayouts build_bind_group_layouts(const ShaderInfo& info, const Shader
|
|||
{
|
||||
const wgpu::BindGroupLayoutDescriptor descriptor{
|
||||
.label = "GX Texture Bind Group",
|
||||
.entryCount = textureCount,
|
||||
.entryCount = numTextures,
|
||||
.entries = textureEntries.data(),
|
||||
};
|
||||
out.textureLayout = g_device.CreateBindGroupLayout(&descriptor);
|
||||
}
|
||||
sTextureBindGroupLayouts.try_emplace(textureCount, out.samplerLayout, out.textureLayout);
|
||||
}
|
||||
// sTextureBindGroupLayouts.try_emplace(textureCount, out.samplerLayout, out.textureLayout);
|
||||
// }
|
||||
return out;
|
||||
}
|
||||
|
||||
|
|
|
@ -173,6 +173,7 @@ struct GXState {
|
|||
std::array<Light, GX::MaxLights> lights;
|
||||
std::array<TevStage, MaxTevStages> tevStages;
|
||||
std::array<TextureBind, MaxTextures> textures;
|
||||
std::array<GXTlutObj, MaxTextures> tluts;
|
||||
std::array<TexMtxVariant, MaxTexMtx> texMtxs;
|
||||
std::array<Mat4x4<float>, MaxPTTexMtx> ptTexMtxs;
|
||||
std::array<TcgConfig, MaxTexCoord> tcgs;
|
||||
|
|
|
@ -562,7 +562,7 @@ static inline std::string vtx_attr(const ShaderConfig& config, GX::Attr attr) {
|
|||
unreachable();
|
||||
}
|
||||
|
||||
static inline std::string texture_conversion(const TextureConfig& tex, u32 stageIdx) {
|
||||
static inline std::string texture_conversion(const TextureConfig& tex, u32 stageIdx, u32 texMapId) {
|
||||
std::string out;
|
||||
switch (tex.copyFmt) {
|
||||
default:
|
||||
|
@ -572,15 +572,25 @@ static inline std::string texture_conversion(const TextureConfig& tex, u32 stage
|
|||
out += fmt::format(FMT_STRING("\n sampled{0}.a = 1.0;"), stageIdx);
|
||||
break;
|
||||
case GX::TF_I4:
|
||||
case GX::TF_I8:
|
||||
// Perform intensity conversion
|
||||
out += fmt::format(
|
||||
FMT_STRING("\n {{"
|
||||
"\n var intensity = dot(sampled{0}.rgb, vec3(0.257, 0.504, 0.098)) + 16.0 / 255.0;"
|
||||
"\n sampled{0} = vec4<f32>(intensity);"
|
||||
"\n sampled{0} = vec4<f32>(intensity, 0.f, 0.f, 1.f);"
|
||||
"\n }}"),
|
||||
stageIdx);
|
||||
break;
|
||||
}
|
||||
switch (tex.loadFmt) {
|
||||
default:
|
||||
break;
|
||||
case GX::TF_I4:
|
||||
case GX::TF_I8:
|
||||
// Splat R to RGBA
|
||||
out += fmt::format(FMT_STRING("\n sampled{0} = vec4<f32>(sampled{0}.r);"), stageIdx);
|
||||
break;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
|
@ -1058,10 +1068,16 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in
|
|||
// } else {
|
||||
uvIn = fmt::format(FMT_STRING("in.tex{0}_uv"), stage.texCoordId);
|
||||
// }
|
||||
if (texConfig.loadFmt == GX::TF_C4 || texConfig.loadFmt == GX::TF_C8 || texConfig.loadFmt == GX::TF_C14X2) {
|
||||
fragmentFnPre +=
|
||||
fmt::format(FMT_STRING("\n var sampled{0} = textureSampleBias(tex{1}, tex{1}_samp, {2}, ubuf.tex{1}_lod);"),
|
||||
fmt::format(FMT_STRING("\n var sampled{0} = textureSamplePalette(tex{1}, tex{1}_samp, {2}, tlut{1});"),
|
||||
i, stage.texMapId, uvIn);
|
||||
fragmentFnPre += texture_conversion(texConfig, i);
|
||||
} else {
|
||||
fragmentFnPre += fmt::format(
|
||||
FMT_STRING("\n var sampled{0} = textureSampleBias(tex{1}, tex{1}_samp, {2}, ubuf.tex{1}_lod);"), i,
|
||||
stage.texMapId, uvIn);
|
||||
}
|
||||
fragmentFnPre += texture_conversion(texConfig, i, stage.texMapId);
|
||||
}
|
||||
for (int i = 0; i < info.usesTexMtx.size(); ++i) {
|
||||
if (info.usesTexMtx.test(i)) {
|
||||
|
@ -1135,9 +1151,21 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in
|
|||
sampBindings += fmt::format(FMT_STRING("\n@group(1) @binding({})\n"
|
||||
"var tex{}_samp: sampler;"),
|
||||
texBindIdx, i);
|
||||
|
||||
const auto& texConfig = config.textureConfig[i];
|
||||
if (texConfig.loadFmt == GX::TF_C4 || texConfig.loadFmt == GX::TF_C8 || texConfig.loadFmt == GX::TF_C14X2) {
|
||||
texBindings += fmt::format(FMT_STRING("\n@group(2) @binding({})\n"
|
||||
"var tex{}: texture_2d<i32>;"),
|
||||
texBindIdx, i);
|
||||
++texBindIdx;
|
||||
texBindings += fmt::format(FMT_STRING("\n@group(2) @binding({})\n"
|
||||
"var tlut{}: texture_2d<f32>;"),
|
||||
texBindIdx, i);
|
||||
} else {
|
||||
texBindings += fmt::format(FMT_STRING("\n@group(2) @binding({})\n"
|
||||
"var tex{}: texture_2d<f32>;"),
|
||||
texBindIdx, i);
|
||||
}
|
||||
++texBindIdx;
|
||||
}
|
||||
|
||||
|
@ -1184,6 +1212,19 @@ struct VertexOutput {{
|
|||
@builtin(position) pos: vec4<f32>,{vtxOutAttrs}
|
||||
}};
|
||||
|
||||
fn textureSamplePalette(tex: texture_2d<i32>, samp: sampler, uv: vec2<f32>, tlut: texture_2d<f32>) -> vec4<f32> {{
|
||||
var f = fract(uv * vec2<f32>(textureDimensions(tex)) + 0.5);
|
||||
var i = textureGather(0, tex, samp, uv);
|
||||
var sX = textureLoad(tlut, vec2<i32>(i.x, 0), 0);
|
||||
var sY = textureLoad(tlut, vec2<i32>(i.y, 0), 0);
|
||||
var sZ = textureLoad(tlut, vec2<i32>(i.z, 0), 0);
|
||||
var sW = textureLoad(tlut, vec2<i32>(i.w, 0), 0);
|
||||
// Bilinear filtering
|
||||
var tA = mix(sW, sZ, f.x);
|
||||
var tB = mix(sX, sY, f.x);
|
||||
return mix(tA, tB, f.y);
|
||||
}}
|
||||
|
||||
@stage(vertex)
|
||||
fn vs_main({vtxInAttrs}
|
||||
) -> VertexOutput {{
|
||||
|
|
|
@ -22,6 +22,8 @@ static TextureFormatInfo format_info(wgpu::TextureFormat format) {
|
|||
switch (format) {
|
||||
case wgpu::TextureFormat::R8Unorm:
|
||||
return {1, 1, 1, false};
|
||||
case wgpu::TextureFormat::R16Sint:
|
||||
return {1, 1, 2, false};
|
||||
case wgpu::TextureFormat::RGBA8Unorm:
|
||||
case wgpu::TextureFormat::R32Float:
|
||||
return {1, 1, 4, false};
|
||||
|
|
|
@ -87,11 +87,11 @@ constexpr T bswap16(T val) noexcept {
|
|||
|
||||
static ByteBuffer BuildI4FromGCN(uint32_t width, uint32_t height, uint32_t mips, ArrayRef<uint8_t> data) {
|
||||
const size_t texelCount = ComputeMippedTexelCount(width, height, mips);
|
||||
ByteBuffer buf{sizeof(RGBA8) * texelCount};
|
||||
ByteBuffer buf{texelCount};
|
||||
|
||||
uint32_t w = width;
|
||||
uint32_t h = height;
|
||||
auto* targetMip = reinterpret_cast<RGBA8*>(buf.data());
|
||||
u8* targetMip = buf.data();
|
||||
const uint8_t* in = data.data();
|
||||
for (uint32_t mip = 0; mip < mips; ++mip) {
|
||||
const uint32_t bwidth = (w + 7) / 8;
|
||||
|
@ -101,12 +101,9 @@ static ByteBuffer BuildI4FromGCN(uint32_t width, uint32_t height, uint32_t mips,
|
|||
for (uint32_t bx = 0; bx < bwidth; ++bx) {
|
||||
const uint32_t baseX = bx * 8;
|
||||
for (uint32_t y = 0; y < std::min(h, 8u); ++y) {
|
||||
RGBA8* target = targetMip + (baseY + y) * w + baseX;
|
||||
u8* target = targetMip + (baseY + y) * w + baseX;
|
||||
for (uint32_t x = 0; x < std::min(w, 8u); ++x) {
|
||||
target[x].r = Convert4To8(in[x / 2] >> ((x & 1) ? 0 : 4) & 0xf);
|
||||
target[x].g = target[x].r;
|
||||
target[x].b = target[x].r;
|
||||
target[x].a = target[x].r;
|
||||
target[x] = Convert4To8(in[x / 2] >> ((x & 1) ? 0 : 4) & 0xf);
|
||||
}
|
||||
in += std::min<size_t>(w / 4, 4);
|
||||
}
|
||||
|
@ -247,13 +244,13 @@ ByteBuffer BuildIA8FromGCN(uint32_t width, uint32_t height, uint32_t mips, Array
|
|||
return buf;
|
||||
}
|
||||
|
||||
ByteBuffer BuildC4FromGCN(uint32_t width, uint32_t height, uint32_t mips, ArrayRef<uint8_t> data, RGBA8* palette) {
|
||||
ByteBuffer BuildC4FromGCN(uint32_t width, uint32_t height, uint32_t mips, ArrayRef<uint8_t> data) {
|
||||
const size_t texelCount = ComputeMippedTexelCount(width, height, mips);
|
||||
ByteBuffer buf{sizeof(RGBA8) * texelCount};
|
||||
ByteBuffer buf{texelCount * 2};
|
||||
|
||||
uint32_t w = width;
|
||||
uint32_t h = height;
|
||||
auto* targetMip = reinterpret_cast<RGBA8*>(buf.data());
|
||||
u16* targetMip = reinterpret_cast<u16*>(buf.data());
|
||||
const uint8_t* in = data.data();
|
||||
for (uint32_t mip = 0; mip < mips; ++mip) {
|
||||
const uint32_t bwidth = (w + 7) / 8;
|
||||
|
@ -262,13 +259,13 @@ ByteBuffer BuildC4FromGCN(uint32_t width, uint32_t height, uint32_t mips, ArrayR
|
|||
const uint32_t baseY = by * 8;
|
||||
for (uint32_t bx = 0; bx < bwidth; ++bx) {
|
||||
const uint32_t baseX = bx * 8;
|
||||
for (uint32_t y = 0; y < 8; ++y) {
|
||||
RGBA8* target = targetMip + (baseY + y) * w + baseX;
|
||||
for (uint32_t y = 0; y < std::min(8u, h); ++y) {
|
||||
u16* target = targetMip + (baseY + y) * w + baseX;
|
||||
const auto n = std::min(w, 8u);
|
||||
for (size_t x = 0; x < n; ++x) {
|
||||
target[x] = palette[in[x / 2] >> ((x & 1) ? 0 : 4) & 0xf];
|
||||
target[x] = in[x / 2] >> ((x & 1) ? 0 : 4) & 0xf;
|
||||
}
|
||||
in += n;
|
||||
in += n / 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -284,13 +281,13 @@ ByteBuffer BuildC4FromGCN(uint32_t width, uint32_t height, uint32_t mips, ArrayR
|
|||
return buf;
|
||||
}
|
||||
|
||||
ByteBuffer BuildC8FromGCN(uint32_t width, uint32_t height, uint32_t mips, ArrayRef<uint8_t> data, RGBA8* palette) {
|
||||
ByteBuffer BuildC8FromGCN(uint32_t width, uint32_t height, uint32_t mips, ArrayRef<uint8_t> data) {
|
||||
const size_t texelCount = ComputeMippedTexelCount(width, height, mips);
|
||||
ByteBuffer buf{sizeof(RGBA8) * texelCount};
|
||||
ByteBuffer buf{texelCount * 2};
|
||||
|
||||
uint32_t w = width;
|
||||
uint32_t h = height;
|
||||
auto* targetMip = reinterpret_cast<RGBA8*>(buf.data());
|
||||
u16* targetMip = reinterpret_cast<u16*>(buf.data());
|
||||
const uint8_t* in = data.data();
|
||||
for (uint32_t mip = 0; mip < mips; ++mip) {
|
||||
const uint32_t bwidth = (w + 7) / 8;
|
||||
|
@ -300,10 +297,10 @@ ByteBuffer BuildC8FromGCN(uint32_t width, uint32_t height, uint32_t mips, ArrayR
|
|||
for (uint32_t bx = 0; bx < bwidth; ++bx) {
|
||||
const uint32_t baseX = bx * 8;
|
||||
for (uint32_t y = 0; y < 4; ++y) {
|
||||
RGBA8* target = targetMip + (baseY + y) * w + baseX;
|
||||
u16* target = targetMip + (baseY + y) * w + baseX;
|
||||
const auto n = std::min(w, 8u);
|
||||
for (size_t x = 0; x < n; ++x) {
|
||||
target[x] = palette[in[x]];
|
||||
target[x] = in[x];
|
||||
}
|
||||
in += n;
|
||||
}
|
||||
|
@ -336,9 +333,9 @@ ByteBuffer BuildRGB565FromGCN(uint32_t width, uint32_t height, uint32_t mips, Ar
|
|||
const uint32_t baseY = by * 4;
|
||||
for (uint32_t bx = 0; bx < bwidth; ++bx) {
|
||||
const uint32_t baseX = bx * 4;
|
||||
for (uint32_t y = 0; y < 4; ++y) {
|
||||
for (uint32_t y = 0; y < std::min(4u, h); ++y) {
|
||||
RGBA8* target = targetMip + (baseY + y) * w + baseX;
|
||||
for (size_t x = 0; x < 4; ++x) {
|
||||
for (size_t x = 0; x < std::min(4u, w); ++x) {
|
||||
const auto texel = bswap16(in[x]);
|
||||
target[x].r = Convert5To8(texel >> 11 & 0x1f);
|
||||
target[x].g = Convert6To8(texel >> 5 & 0x3f);
|
||||
|
@ -376,9 +373,9 @@ ByteBuffer BuildRGB5A3FromGCN(uint32_t width, uint32_t height, uint32_t mips, Ar
|
|||
const uint32_t baseY = by * 4;
|
||||
for (uint32_t bx = 0; bx < bwidth; ++bx) {
|
||||
const uint32_t baseX = bx * 4;
|
||||
for (uint32_t y = 0; y < 4; ++y) {
|
||||
for (uint32_t y = 0; y < std::min(4u, h); ++y) {
|
||||
RGBA8* target = targetMip + (baseY + y) * w + baseX;
|
||||
for (size_t x = 0; x < 4; ++x) {
|
||||
for (size_t x = 0; x < std::min(4u, w); ++x) {
|
||||
const auto texel = bswap16(in[x]);
|
||||
if ((texel & 0x8000) != 0) {
|
||||
target[x].r = Convert5To8(texel >> 10 & 0x1f);
|
||||
|
@ -599,13 +596,9 @@ ByteBuffer convert_texture(GX::TextureFormat format, uint32_t width, uint32_t he
|
|||
case GX::TF_IA8:
|
||||
return BuildIA8FromGCN(width, height, mips, data);
|
||||
case GX::TF_C4:
|
||||
Log.report(logvisor::Fatal, FMT_STRING("convert_texture: C4 unimplemented"));
|
||||
unreachable();
|
||||
// return BuildC4FromGCN(width, height, mips, data);
|
||||
return BuildC4FromGCN(width, height, mips, data);
|
||||
case GX::TF_C8:
|
||||
Log.report(logvisor::Fatal, FMT_STRING("convert_texture: C8 unimplemented"));
|
||||
unreachable();
|
||||
// return BuildC8FromGCN(width, height, mips, data);
|
||||
return BuildC8FromGCN(width, height, mips, data);
|
||||
case GX::TF_C14X2:
|
||||
Log.report(logvisor::Fatal, FMT_STRING("convert_texture: C14X2 unimplemented"));
|
||||
unreachable();
|
||||
|
|
|
@ -7,9 +7,13 @@
|
|||
namespace aurora::gfx {
|
||||
static wgpu::TextureFormat to_wgpu(GX::TextureFormat format) {
|
||||
switch (format) {
|
||||
case GX::TF_C8:
|
||||
case GX::TF_I4:
|
||||
case GX::TF_I8:
|
||||
return wgpu::TextureFormat::R8Unorm;
|
||||
case GX::TF_C4:
|
||||
case GX::TF_C8:
|
||||
case GX::TF_C14X2:
|
||||
return wgpu::TextureFormat::R16Sint;
|
||||
case GX::TF_CMPR:
|
||||
if (gpu::g_device.HasFeature(wgpu::FeatureName::TextureCompressionBC)) {
|
||||
return wgpu::TextureFormat::BC1RGBAUnorm;
|
||||
|
|
|
@ -285,10 +285,11 @@ void initialize(SDL_Window* window) {
|
|||
"use_dxc",
|
||||
#endif
|
||||
#ifdef NDEBUG
|
||||
"skip_validation", "disable_robustness",
|
||||
#else
|
||||
"use_user_defined_labels_in_backend",
|
||||
"skip_validation",
|
||||
"disable_robustness",
|
||||
#endif
|
||||
"use_user_defined_labels_in_backend",
|
||||
"disable_symbol_renaming",
|
||||
/* clang-format on */
|
||||
};
|
||||
wgpu::DawnTogglesDeviceDescriptor togglesDescriptor{};
|
||||
|
|
Loading…
Reference in New Issue