libretro-dolphin/Source/Core/VideoCommon/AbstractTexture.cpp
Stenzek 06daf58032 FramebufferManager: Correctly handle read back D24S8 textures
Needed for the Adreno/Vulkan workaround, and if we ever switch to a D24
texture for the depth buffer w/ unrestricted depth range.
2019-07-31 15:33:28 +10:00

180 lines
4.9 KiB
C++

// Copyright 2017 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <algorithm>
#include "Common/Assert.h"
#include "Common/MsgHandler.h"
#include "VideoCommon/AbstractStagingTexture.h"
#include "VideoCommon/AbstractTexture.h"
#include "VideoCommon/ImageWrite.h"
#include "VideoCommon/RenderBase.h"
AbstractTexture::AbstractTexture(const TextureConfig& c) : m_config(c)
{
}
void AbstractTexture::FinishedRendering()
{
}
bool AbstractTexture::Save(const std::string& filename, unsigned int level)
{
// We can't dump compressed textures currently (it would mean drawing them to a RGBA8
// framebuffer, and saving that). TextureCache does not call Save for custom textures
// anyway, so this is fine for now.
ASSERT(!IsCompressedFormat(m_config.format));
ASSERT(level < m_config.levels);
// Determine dimensions of image we want to save.
u32 level_width = std::max(1u, m_config.width >> level);
u32 level_height = std::max(1u, m_config.height >> level);
// Use a temporary staging texture for the download. Certainly not optimal,
// but this is not a frequently-executed code path..
TextureConfig readback_texture_config(level_width, level_height, 1, 1, 1,
AbstractTextureFormat::RGBA8, 0);
auto readback_texture =
g_renderer->CreateStagingTexture(StagingTextureType::Readback, readback_texture_config);
if (!readback_texture)
return false;
// Copy to the readback texture's buffer.
readback_texture->CopyFromTexture(this, 0, level);
readback_texture->Flush();
// Map it so we can encode it to the file.
if (!readback_texture->Map())
return false;
return TextureToPng(reinterpret_cast<const u8*>(readback_texture->GetMappedPointer()),
static_cast<int>(readback_texture->GetMappedStride()), filename, level_width,
level_height);
}
bool AbstractTexture::IsCompressedFormat(AbstractTextureFormat format)
{
switch (format)
{
case AbstractTextureFormat::DXT1:
case AbstractTextureFormat::DXT3:
case AbstractTextureFormat::DXT5:
case AbstractTextureFormat::BPTC:
return true;
default:
return false;
}
}
bool AbstractTexture::IsDepthFormat(AbstractTextureFormat format)
{
switch (format)
{
case AbstractTextureFormat::D16:
case AbstractTextureFormat::D24_S8:
case AbstractTextureFormat::D32F:
case AbstractTextureFormat::D32F_S8:
return true;
default:
return false;
}
}
bool AbstractTexture::IsStencilFormat(AbstractTextureFormat format)
{
return format == AbstractTextureFormat::D24_S8 || format == AbstractTextureFormat::D32F_S8;
}
bool AbstractTexture::IsCompatibleDepthAndColorFormats(AbstractTextureFormat depth_format,
AbstractTextureFormat color_format)
{
switch (depth_format)
{
case AbstractTextureFormat::D16:
return color_format == AbstractTextureFormat::R16;
case AbstractTextureFormat::D32F:
return color_format == AbstractTextureFormat::R32F;
default:
return false;
}
}
u32 AbstractTexture::CalculateStrideForFormat(AbstractTextureFormat format, u32 row_length)
{
switch (format)
{
case AbstractTextureFormat::DXT1:
return static_cast<size_t>(std::max(1u, row_length / 4)) * 8;
case AbstractTextureFormat::DXT3:
case AbstractTextureFormat::DXT5:
case AbstractTextureFormat::BPTC:
return static_cast<size_t>(std::max(1u, row_length / 4)) * 16;
case AbstractTextureFormat::R16:
case AbstractTextureFormat::D16:
return static_cast<size_t>(row_length) * 2;
case AbstractTextureFormat::RGBA8:
case AbstractTextureFormat::BGRA8:
case AbstractTextureFormat::R32F:
case AbstractTextureFormat::D32F:
case AbstractTextureFormat::D24_S8:
return static_cast<size_t>(row_length) * 4;
case AbstractTextureFormat::D32F_S8:
return static_cast<size_t>(row_length) * 8;
default:
PanicAlert("Unhandled texture format.");
return 0;
}
}
u32 AbstractTexture::GetTexelSizeForFormat(AbstractTextureFormat format)
{
switch (format)
{
case AbstractTextureFormat::DXT1:
return 8;
case AbstractTextureFormat::DXT3:
case AbstractTextureFormat::DXT5:
case AbstractTextureFormat::BPTC:
return 16;
case AbstractTextureFormat::R16:
case AbstractTextureFormat::D16:
return 2;
case AbstractTextureFormat::RGBA8:
case AbstractTextureFormat::BGRA8:
case AbstractTextureFormat::D24_S8:
case AbstractTextureFormat::R32F:
case AbstractTextureFormat::D32F:
return 4;
case AbstractTextureFormat::D32F_S8:
return 8;
default:
PanicAlert("Unhandled texture format.");
return 0;
}
}
u32 AbstractTexture::GetBlockSizeForFormat(AbstractTextureFormat format)
{
switch (format)
{
case AbstractTextureFormat::DXT1:
case AbstractTextureFormat::DXT3:
case AbstractTextureFormat::DXT5:
case AbstractTextureFormat::BPTC:
return 4;
default:
return 1;
}
}
const TextureConfig& AbstractTexture::GetConfig() const
{
return m_config;
}