aurora: Working palette textures

This commit is contained in:
Luke Street 2022-05-14 19:23:47 -04:00
parent ef771e6489
commit ef71c009c6
10 changed files with 221 additions and 98 deletions

View File

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

View File

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

View File

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

View File

@ -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 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();
}
void GXLoadTlut(const GXTlutObj* obj, GXTlut idx) noexcept {
// TODO
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;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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