mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2024-12-30 20:20:52 +01:00
12dd15c8dd
Co-authored-by: TellowKrinkle <tellowkrinkle@gmail.com>
189 lines
5.4 KiB
C++
189 lines
5.4 KiB
C++
// Copyright 2017 Dolphin Emulator Project
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
#include "VideoCommon/AbstractTexture.h"
|
|
|
|
#include <algorithm>
|
|
|
|
#include "Common/Assert.h"
|
|
#include "Common/Image.h"
|
|
#include "Common/MsgHandler.h"
|
|
#include "VideoCommon/AbstractGfx.h"
|
|
#include "VideoCommon/AbstractStagingTexture.h"
|
|
|
|
AbstractTexture::AbstractTexture(const TextureConfig& c) : m_config(c)
|
|
{
|
|
}
|
|
|
|
void AbstractTexture::FinishedRendering()
|
|
{
|
|
}
|
|
|
|
bool AbstractTexture::Save(const std::string& filename, unsigned int level, int compression) const
|
|
{
|
|
// 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);
|
|
// We can't copy from float (HDR) textures to RGBA8
|
|
// (most other formats would probably fail as well)
|
|
ASSERT(m_config.format != AbstractTextureFormat::RGBA16F);
|
|
|
|
// 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,
|
|
AbstractTextureType::Texture_2DArray);
|
|
auto readback_texture =
|
|
g_gfx->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 Common::SavePNG(filename,
|
|
reinterpret_cast<const u8*>(readback_texture->GetMappedPointer()),
|
|
Common::ImageByteFormat::RGBA, level_width, level_height,
|
|
static_cast<int>(readback_texture->GetMappedStride()), compression);
|
|
}
|
|
|
|
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::RGB10_A2:
|
|
case AbstractTextureFormat::R32F:
|
|
case AbstractTextureFormat::D32F:
|
|
case AbstractTextureFormat::D24_S8:
|
|
return static_cast<size_t>(row_length) * 4;
|
|
case AbstractTextureFormat::D32F_S8:
|
|
case AbstractTextureFormat::RGBA16F:
|
|
return static_cast<size_t>(row_length) * 8;
|
|
default:
|
|
PanicAlertFmt("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::RGB10_A2:
|
|
case AbstractTextureFormat::D24_S8:
|
|
case AbstractTextureFormat::R32F:
|
|
case AbstractTextureFormat::D32F:
|
|
return 4;
|
|
case AbstractTextureFormat::D32F_S8:
|
|
case AbstractTextureFormat::RGBA16F:
|
|
return 8;
|
|
default:
|
|
PanicAlertFmt("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;
|
|
}
|