Fix Cool Edge whale not having reflections. (#1441)
Some checks failed
validate-internal / build (push) Failing after 9s

* Fix Cool Edge whale not having reflections.

* Fix Vulkan validation error.
This commit is contained in:
Skyth (Asilkan) 2025-03-23 18:59:10 +03:00 committed by GitHub
parent 41fd1761b1
commit a02f34b028
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 59 additions and 13 deletions

View file

@ -683,6 +683,9 @@ static void DestructTempResources()
if (texture->patchedTexture != nullptr)
g_textureDescriptorAllocator.free(texture->patchedTexture->descriptorIndex);
if (texture->recreatedCubeMapTexture != nullptr)
g_textureDescriptorAllocator.free(texture->recreatedCubeMapTexture->descriptorIndex);
texture->~GuestTexture();
break;
}
@ -3647,6 +3650,14 @@ static void SetTextureInRenderThread(uint32_t index, GuestTexture* texture)
SetDirtyValue(g_dirtyStates.sharedConstants, g_sharedConstants.texture3DIndices[index], texture != nullptr &&
viewDimension == RenderTextureViewDimension::TEXTURE_3D ? texture->descriptorIndex : TEXTURE_DESCRIPTOR_NULL_TEXTURE_3D);
// Check if there's a cubemap texture we recreated and assign it if it's valid. The shader will pick whichever is correct.
if (viewDimension == RenderTextureViewDimension::TEXTURE_2D && texture->recreatedCubeMapTexture != nullptr)
{
texture = texture->recreatedCubeMapTexture.get();
AddBarrier(texture, RenderTextureLayout::SHADER_READ);
viewDimension = texture->viewDimension;
}
SetDirtyValue(g_dirtyStates.sharedConstants, g_sharedConstants.textureCubeIndices[index], texture != nullptr &&
viewDimension == RenderTextureViewDimension::TEXTURE_CUBE ? texture->descriptorIndex : TEXTURE_DESCRIPTOR_NULL_TEXTURE_CUBE);
}
@ -5477,21 +5488,30 @@ static RenderFormat ConvertDXGIFormat(ddspp::DXGIFormat format)
}
}
static bool LoadTexture(GuestTexture& texture, const uint8_t* data, size_t dataSize, RenderComponentMapping componentMapping)
static bool LoadTexture(GuestTexture& texture, const uint8_t* data, size_t dataSize, RenderComponentMapping componentMapping, bool forceCubeMap = false)
{
ddspp::Descriptor ddsDesc;
if (ddspp::decode_header((unsigned char *)(data), ddsDesc) != ddspp::Error)
{
forceCubeMap &= (ddsDesc.type == ddspp::Texture2D) && (ddsDesc.arraySize == 1);
uint32_t arraySize = ddsDesc.type == ddspp::TextureType::Cubemap ? (ddsDesc.arraySize * 6) : ddsDesc.arraySize;
RenderTextureDesc desc;
desc.dimension = ConvertTextureDimension(ddsDesc.type);
desc.width = ddsDesc.width;
desc.height = ddsDesc.height;
desc.depth = ddsDesc.depth;
desc.mipLevels = ddsDesc.numMips;
desc.arraySize = ddsDesc.type == ddspp::TextureType::Cubemap ? ddsDesc.arraySize * 6 : ddsDesc.arraySize;
desc.arraySize = arraySize;
desc.format = ConvertDXGIFormat(ddsDesc.format);
desc.flags = ddsDesc.type == ddspp::TextureType::Cubemap ? RenderTextureFlag::CUBE : RenderTextureFlag::NONE;
if (forceCubeMap)
{
desc.arraySize = 6;
desc.flags = RenderTextureFlag::CUBE;
}
texture.textureHolder = g_device->createTexture(desc);
texture.texture = texture.textureHolder.get();
texture.layout = RenderTextureLayout::COPY_DEST;
@ -5501,6 +5521,10 @@ static bool LoadTexture(GuestTexture& texture, const uint8_t* data, size_t dataS
viewDesc.dimension = ConvertTextureViewDimension(ddsDesc.type);
viewDesc.mipLevels = ddsDesc.numMips;
viewDesc.componentMapping = componentMapping;
if (forceCubeMap)
viewDesc.dimension = RenderTextureViewDimension::TEXTURE_CUBE;
texture.textureView = texture.texture->createTextureView(viewDesc);
texture.descriptorIndex = g_textureDescriptorAllocator.allocate();
g_textureDescriptorSet->setTexture(texture.descriptorIndex, texture.texture, RenderTextureLayout::SHADER_READ, texture.textureView.get());
@ -5525,7 +5549,7 @@ static bool LoadTexture(GuestTexture& texture, const uint8_t* data, size_t dataS
uint32_t curSrcOffset = 0;
uint32_t curDstOffset = 0;
for (uint32_t arraySlice = 0; arraySlice < desc.arraySize; arraySlice++)
for (uint32_t arraySlice = 0; arraySlice < arraySize; arraySlice++)
{
for (uint32_t mipSlice = 0; mipSlice < ddsDesc.numMips; mipSlice++)
{
@ -5575,13 +5599,24 @@ static bool LoadTexture(GuestTexture& texture, const uint8_t* data, size_t dataS
{
g_copyCommandList->barriers(RenderBarrierStage::COPY, RenderTextureBarrier(texture.texture, RenderTextureLayout::COPY_DEST));
for (size_t i = 0; i < slices.size(); i++)
{
auto& slice = slices[i];
auto copyTextureRegion = [&](Slice& slice, uint32_t subresourceIndex)
{
g_copyCommandList->copyTextureRegion(
RenderTextureCopyLocation::Subresource(texture.texture, subresourceIndex),
RenderTextureCopyLocation::PlacedFootprint(uploadBuffer.get(), desc.format, slice.width, slice.height, slice.depth, (slice.dstRowPitch * 8) / ddsDesc.bitsPerPixelOrBlock * ddsDesc.blockWidth, slice.dstOffset));
};
g_copyCommandList->copyTextureRegion(
RenderTextureCopyLocation::Subresource(texture.texture, i),
RenderTextureCopyLocation::PlacedFootprint(uploadBuffer.get(), desc.format, slice.width, slice.height, slice.depth, (slice.dstRowPitch * 8) / ddsDesc.bitsPerPixelOrBlock * ddsDesc.blockWidth, slice.dstOffset));
for (size_t i = 0; i < slices.size(); i++)
copyTextureRegion(slices[i], i);
// Duplicate the first face across the remaining 6 faces.
if (forceCubeMap)
{
for (size_t i = 1; i < 6; i++)
{
for (size_t j = 0; j < slices.size(); j++)
copyTextureRegion(slices[j], (slices.size() * i) + j);
}
}
});
@ -5654,13 +5689,12 @@ std::unique_ptr<GuestTexture> LoadTexture(const uint8_t* data, size_t dataSize,
return nullptr;
}
static void DiffPatchTexture(GuestTexture& texture, uint8_t* data, uint32_t dataSize)
static void DiffPatchTexture(GuestTexture& texture, uint8_t* data, uint32_t dataSize, XXH64_hash_t hash)
{
auto header = reinterpret_cast<BlockCompressionDiffPatchHeader*>(g_buttonBcDiff.get());
auto entries = reinterpret_cast<BlockCompressionDiffPatchEntry*>(g_buttonBcDiff.get() + header->entriesOffset);
auto end = entries + header->entryCount;
XXH64_hash_t hash = XXH3_64bits(data, dataSize);
auto findResult = std::lower_bound(entries, end, hash, [](BlockCompressionDiffPatchEntry& lhs, XXH64_hash_t rhs)
{
return lhs.hash < rhs;
@ -5693,8 +5727,19 @@ static void MakePictureData(GuestPictureData* pictureData, uint8_t* data, uint32
#ifdef _DEBUG
texture.texture->setName(reinterpret_cast<char*>(g_memory.Translate(pictureData->name + 2)));
#endif
XXH64_hash_t hash = XXH3_64bits(data, dataSize);
DiffPatchTexture(texture, data, dataSize);
// The whale in Cool Edge has a 2D texture assigned as a cubemap which makes it not display in recomp.
// The hardware duplicates the first face to the remaining 6 faces, so to simulate that we'll recreate the asset.
bool forceCubeMap = (dataSize == 0xAB38) && (hash == 0x160E9E250FDE88A9);
if (forceCubeMap)
{
GuestTexture recreatedCubeMapTexture(ResourceType::Texture);
if (LoadTexture(recreatedCubeMapTexture, data, dataSize, {}, true))
texture.recreatedCubeMapTexture = std::make_unique<GuestTexture>(std::move(recreatedCubeMapTexture));
}
DiffPatchTexture(texture, data, dataSize, hash);
pictureData->texture = g_memory.MapVirtual(g_userHeap.AllocPhysical<GuestTexture>(std::move(texture)));
pictureData->type = 0;

View file

@ -158,6 +158,7 @@ struct GuestTexture : GuestBaseTexture
void* mappedMemory = nullptr;
std::unique_ptr<RenderFramebuffer> framebuffer;
std::unique_ptr<GuestTexture> patchedTexture;
std::unique_ptr<GuestTexture> recreatedCubeMapTexture;
struct GuestSurface* sourceSurface = nullptr;
};