diff --git a/Runtime/Graphics/GX.hpp b/Runtime/Graphics/GX.hpp index f855b49ce..87ea6261f 100644 --- a/Runtime/Graphics/GX.hpp +++ b/Runtime/Graphics/GX.hpp @@ -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 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 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, diff --git a/Runtime/GuiSys/CRasterFont.cpp b/Runtime/GuiSys/CRasterFont.cpp index dddd9b007..cc9b3ae42 100644 --- a/Runtime/GuiSys/CRasterFont.cpp +++ b/Runtime/GuiSys/CRasterFont.cpp @@ -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(pal.GetPaletteData() + 0) = SBIG(zeus::CColor(0.f, 0.f, 0.f, 0.f).toRGB5A3()); - *reinterpret_cast(pal.GetPaletteData() + 2) = SBIG(opts.x4_colors[0].toRGB5A3()); - *reinterpret_cast(pal.GetPaletteData() + 4) = SBIG(opts.x4_colors[1].toRGB5A3()); - *reinterpret_cast(pal.GetPaletteData() + 6) = SBIG(zeus::CColor(0.f, 0.f, 0.f, 0.f).toRGB5A3()); + *reinterpret_cast(pal.GetPaletteData() + 0) = bswap16(zeus::CColor(0.f, 0.f, 0.f, 0.f).toRGB5A3()); + *reinterpret_cast(pal.GetPaletteData() + 2) = bswap16(opts.x4_colors[0].toRGB5A3()); + *reinterpret_cast(pal.GetPaletteData() + 4) = bswap16(opts.x4_colors[1].toRGB5A3()); + *reinterpret_cast(pal.GetPaletteData() + 6) = bswap16(zeus::CColor(0.f, 0.f, 0.f, 0.f).toRGB5A3()); pal.UnLock(); renderBuf->AddPaletteChange(pal); } diff --git a/Runtime/GuiSys/CTextRenderBuffer.cpp b/Runtime/GuiSys/CTextRenderBuffer.cpp index ff4c76f73..335bdd715 100644 --- a/Runtime/GuiSys/CTextRenderBuffer.cpp +++ b/Runtime/GuiSys/CTextRenderBuffer.cpp @@ -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(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(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); diff --git a/aurora/lib/gfx/gx.cpp b/aurora/lib/gfx/gx.cpp index 8ed95d84b..68df28e08 100644 --- a/aurora/lib/gfx/gx.cpp +++ b/aurora/lib/gfx/gx.cpp @@ -493,7 +493,7 @@ void GXSetIndTexMtx(GX::IndTexMtxID id, const void* mtx, s8 scaleExp) noexcept { g_gxState.indTexMtxs[id - 1] = {*static_cast*>(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(format); + obj->wrapS = wrapS; + obj->wrapT = wrapT; + obj->hasMips = mipmap; + obj->tlut = static_cast(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(data), static_cast(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 samplerEntries; - std::array textureEntries; + std::array 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,34 +1200,62 @@ 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 samplerEntries; - std::array textureEntries; - for (u32 i = 0; i < textureCount; ++i) { + std::array 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, - .visibility = wgpu::ShaderStage::Fragment, - .texture = - { - .sampleType = wgpu::TextureSampleType::Float, - .viewDimension = wgpu::TextureViewDimension::e2D, - }, - }; + ++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 = + { + .sampleType = wgpu::TextureSampleType::Float, + .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; } diff --git a/aurora/lib/gfx/gx.hpp b/aurora/lib/gfx/gx.hpp index 439ed1a68..63150dbac 100644 --- a/aurora/lib/gfx/gx.hpp +++ b/aurora/lib/gfx/gx.hpp @@ -173,6 +173,7 @@ struct GXState { std::array lights; std::array tevStages; std::array textures; + std::array tluts; std::array texMtxs; std::array, MaxPTTexMtx> ptTexMtxs; std::array tcgs; diff --git a/aurora/lib/gfx/gx_shader.cpp b/aurora/lib/gfx/gx_shader.cpp index 071167afc..2b7c1271e 100644 --- a/aurora/lib/gfx/gx_shader.cpp +++ b/aurora/lib/gfx/gx_shader.cpp @@ -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(intensity);" + "\n sampled{0} = vec4(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(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); // } - 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); + 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} = textureSamplePalette(tex{1}, tex{1}_samp, {2}, tlut{1});"), + i, stage.texMapId, uvIn); + } 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); - texBindings += fmt::format(FMT_STRING("\n@group(2) @binding({})\n" - "var tex{}: texture_2d;"), - 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;"), + texBindIdx, i); + ++texBindIdx; + texBindings += fmt::format(FMT_STRING("\n@group(2) @binding({})\n" + "var tlut{}: texture_2d;"), + texBindIdx, i); + } else { + texBindings += fmt::format(FMT_STRING("\n@group(2) @binding({})\n" + "var tex{}: texture_2d;"), + texBindIdx, i); + } ++texBindIdx; } @@ -1184,6 +1212,19 @@ struct VertexOutput {{ @builtin(position) pos: vec4,{vtxOutAttrs} }}; +fn textureSamplePalette(tex: texture_2d, samp: sampler, uv: vec2, tlut: texture_2d) -> vec4 {{ + var f = fract(uv * vec2(textureDimensions(tex)) + 0.5); + var i = textureGather(0, tex, samp, uv); + var sX = textureLoad(tlut, vec2(i.x, 0), 0); + var sY = textureLoad(tlut, vec2(i.y, 0), 0); + var sZ = textureLoad(tlut, vec2(i.z, 0), 0); + var sW = textureLoad(tlut, vec2(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 {{ diff --git a/aurora/lib/gfx/texture.cpp b/aurora/lib/gfx/texture.cpp index b42410667..874f4568a 100644 --- a/aurora/lib/gfx/texture.cpp +++ b/aurora/lib/gfx/texture.cpp @@ -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}; diff --git a/aurora/lib/gfx/texture_convert.cpp b/aurora/lib/gfx/texture_convert.cpp index 7eb03efe6..ee72cc130 100644 --- a/aurora/lib/gfx/texture_convert.cpp +++ b/aurora/lib/gfx/texture_convert.cpp @@ -87,11 +87,11 @@ constexpr T bswap16(T val) noexcept { static ByteBuffer BuildI4FromGCN(uint32_t width, uint32_t height, uint32_t mips, ArrayRef 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(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(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 data, RGBA8* palette) { +ByteBuffer BuildC4FromGCN(uint32_t width, uint32_t height, uint32_t mips, ArrayRef 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(buf.data()); + u16* targetMip = reinterpret_cast(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 data, RGBA8* palette) { +ByteBuffer BuildC8FromGCN(uint32_t width, uint32_t height, uint32_t mips, ArrayRef 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(buf.data()); + u16* targetMip = reinterpret_cast(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(); diff --git a/aurora/lib/gfx/texture_convert.hpp b/aurora/lib/gfx/texture_convert.hpp index 64dc78549..54f49270f 100644 --- a/aurora/lib/gfx/texture_convert.hpp +++ b/aurora/lib/gfx/texture_convert.hpp @@ -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; diff --git a/aurora/lib/gpu.cpp b/aurora/lib/gpu.cpp index ae7f9edb5..7eb7100e6 100644 --- a/aurora/lib/gpu.cpp +++ b/aurora/lib/gpu.cpp @@ -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{};