2017-04-22 22:44:34 -06:00
|
|
|
// Copyright 2017 Dolphin Emulator Project
|
2021-07-04 19:22:19 -06:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2017-04-22 22:44:34 -06:00
|
|
|
|
2021-12-09 19:22:16 -07:00
|
|
|
#include "VideoCommon/AbstractTexture.h"
|
|
|
|
|
2017-04-22 22:44:34 -06:00
|
|
|
#include <algorithm>
|
|
|
|
|
2017-05-30 22:44:03 -06:00
|
|
|
#include "Common/Assert.h"
|
2020-12-16 07:34:50 -07:00
|
|
|
#include "Common/Image.h"
|
2017-09-08 23:24:41 -06:00
|
|
|
#include "Common/MsgHandler.h"
|
2023-01-26 15:34:59 -07:00
|
|
|
#include "VideoCommon/AbstractGfx.h"
|
2017-10-30 06:00:15 -06:00
|
|
|
#include "VideoCommon/AbstractStagingTexture.h"
|
2017-04-22 22:44:34 -06:00
|
|
|
|
2017-11-18 23:23:19 -07:00
|
|
|
AbstractTexture::AbstractTexture(const TextureConfig& c) : m_config(c)
|
2017-04-22 22:44:34 -06:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-02-14 18:59:50 -07:00
|
|
|
void AbstractTexture::FinishedRendering()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2023-02-09 07:49:25 -07:00
|
|
|
bool AbstractTexture::Save(const std::string& filename, unsigned int level, int compression)
|
2017-04-22 22:44:34 -06:00
|
|
|
{
|
2017-05-30 22:44:03 -06:00
|
|
|
// 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.
|
2018-03-14 18:34:35 -06:00
|
|
|
ASSERT(!IsCompressedFormat(m_config.format));
|
|
|
|
ASSERT(level < m_config.levels);
|
2023-06-07 18:17:20 -06:00
|
|
|
// We can't copy from float (HDR) textures to RGBA8
|
|
|
|
// (most other formats would probably fail as well)
|
|
|
|
ASSERT(m_config.format != AbstractTextureFormat::RGBA16F);
|
2017-05-30 22:44:03 -06:00
|
|
|
|
2017-10-30 06:00:15 -06:00
|
|
|
// 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..
|
2018-01-20 22:03:06 -07:00
|
|
|
TextureConfig readback_texture_config(level_width, level_height, 1, 1, 1,
|
2019-02-14 18:59:50 -07:00
|
|
|
AbstractTextureFormat::RGBA8, 0);
|
2017-10-30 06:00:15 -06:00
|
|
|
auto readback_texture =
|
2023-01-26 15:34:59 -07:00
|
|
|
g_gfx->CreateStagingTexture(StagingTextureType::Readback, readback_texture_config);
|
2017-10-30 06:00:15 -06:00
|
|
|
if (!readback_texture)
|
|
|
|
return false;
|
2017-05-30 22:44:03 -06:00
|
|
|
|
2017-10-30 06:00:15 -06:00
|
|
|
// 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())
|
2017-05-30 22:44:03 -06:00
|
|
|
return false;
|
|
|
|
|
2020-12-16 07:34:50 -07:00
|
|
|
return Common::SavePNG(filename,
|
|
|
|
reinterpret_cast<const u8*>(readback_texture->GetMappedPointer()),
|
|
|
|
Common::ImageByteFormat::RGBA, level_width, level_height,
|
2023-02-09 07:49:25 -07:00
|
|
|
static_cast<int>(readback_texture->GetMappedStride()), compression);
|
2017-05-30 22:44:03 -06:00
|
|
|
}
|
|
|
|
|
2017-10-21 08:49:40 -06:00
|
|
|
bool AbstractTexture::IsCompressedFormat(AbstractTextureFormat format)
|
2017-04-22 22:44:34 -06:00
|
|
|
{
|
2017-09-08 23:24:41 -06:00
|
|
|
switch (format)
|
|
|
|
{
|
|
|
|
case AbstractTextureFormat::DXT1:
|
|
|
|
case AbstractTextureFormat::DXT3:
|
|
|
|
case AbstractTextureFormat::DXT5:
|
|
|
|
case AbstractTextureFormat::BPTC:
|
|
|
|
return true;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
2017-04-22 22:44:34 -06:00
|
|
|
}
|
|
|
|
|
2018-01-21 06:59:19 -07:00
|
|
|
bool AbstractTexture::IsDepthFormat(AbstractTextureFormat format)
|
|
|
|
{
|
|
|
|
switch (format)
|
|
|
|
{
|
|
|
|
case AbstractTextureFormat::D16:
|
2018-07-16 21:22:48 -06:00
|
|
|
case AbstractTextureFormat::D24_S8:
|
2018-01-21 06:59:19 -07:00
|
|
|
case AbstractTextureFormat::D32F:
|
|
|
|
case AbstractTextureFormat::D32F_S8:
|
|
|
|
return true;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-21 03:22:45 -07:00
|
|
|
bool AbstractTexture::IsStencilFormat(AbstractTextureFormat format)
|
|
|
|
{
|
2018-07-16 21:22:48 -06:00
|
|
|
return format == AbstractTextureFormat::D24_S8 || format == AbstractTextureFormat::D32F_S8;
|
2018-01-21 03:22:45 -07:00
|
|
|
}
|
|
|
|
|
2019-07-30 23:33:27 -06:00
|
|
|
bool AbstractTexture::IsCompatibleDepthAndColorFormats(AbstractTextureFormat depth_format,
|
|
|
|
AbstractTextureFormat color_format)
|
2019-02-14 18:59:50 -07:00
|
|
|
{
|
2019-07-30 23:33:27 -06:00
|
|
|
switch (depth_format)
|
2019-02-14 18:59:50 -07:00
|
|
|
{
|
|
|
|
case AbstractTextureFormat::D16:
|
2019-07-30 23:33:27 -06:00
|
|
|
return color_format == AbstractTextureFormat::R16;
|
2019-02-14 18:59:50 -07:00
|
|
|
|
|
|
|
case AbstractTextureFormat::D32F:
|
2019-07-30 23:33:27 -06:00
|
|
|
return color_format == AbstractTextureFormat::R32F;
|
2019-02-14 18:59:50 -07:00
|
|
|
|
|
|
|
default:
|
2019-07-30 23:33:27 -06:00
|
|
|
return false;
|
2019-02-14 18:59:50 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
u32 AbstractTexture::CalculateStrideForFormat(AbstractTextureFormat format, u32 row_length)
|
2017-04-22 22:44:34 -06:00
|
|
|
{
|
|
|
|
switch (format)
|
|
|
|
{
|
2017-06-12 11:37:28 -06:00
|
|
|
case AbstractTextureFormat::DXT1:
|
2017-04-22 22:44:34 -06:00
|
|
|
return static_cast<size_t>(std::max(1u, row_length / 4)) * 8;
|
2017-06-12 11:37:28 -06:00
|
|
|
case AbstractTextureFormat::DXT3:
|
|
|
|
case AbstractTextureFormat::DXT5:
|
2017-07-27 06:00:04 -06:00
|
|
|
case AbstractTextureFormat::BPTC:
|
2017-04-22 22:44:34 -06:00
|
|
|
return static_cast<size_t>(std::max(1u, row_length / 4)) * 16;
|
2018-01-21 06:59:19 -07:00
|
|
|
case AbstractTextureFormat::R16:
|
|
|
|
case AbstractTextureFormat::D16:
|
|
|
|
return static_cast<size_t>(row_length) * 2;
|
2017-06-12 11:37:28 -06:00
|
|
|
case AbstractTextureFormat::RGBA8:
|
2017-09-08 23:24:41 -06:00
|
|
|
case AbstractTextureFormat::BGRA8:
|
2023-06-07 18:17:20 -06:00
|
|
|
case AbstractTextureFormat::RGB10_A2:
|
2018-01-21 06:59:19 -07:00
|
|
|
case AbstractTextureFormat::R32F:
|
|
|
|
case AbstractTextureFormat::D32F:
|
2018-07-16 21:22:48 -06:00
|
|
|
case AbstractTextureFormat::D24_S8:
|
2017-04-22 22:44:34 -06:00
|
|
|
return static_cast<size_t>(row_length) * 4;
|
2018-01-21 06:59:19 -07:00
|
|
|
case AbstractTextureFormat::D32F_S8:
|
2023-06-07 18:17:20 -06:00
|
|
|
case AbstractTextureFormat::RGBA16F:
|
2018-01-21 06:59:19 -07:00
|
|
|
return static_cast<size_t>(row_length) * 8;
|
2017-09-08 23:24:41 -06:00
|
|
|
default:
|
2020-11-13 20:33:26 -07:00
|
|
|
PanicAlertFmt("Unhandled texture format.");
|
2017-09-08 23:24:41 -06:00
|
|
|
return 0;
|
2017-04-22 22:44:34 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-14 18:59:50 -07:00
|
|
|
u32 AbstractTexture::GetTexelSizeForFormat(AbstractTextureFormat format)
|
2017-10-21 08:49:40 -06:00
|
|
|
{
|
|
|
|
switch (format)
|
|
|
|
{
|
|
|
|
case AbstractTextureFormat::DXT1:
|
|
|
|
return 8;
|
|
|
|
case AbstractTextureFormat::DXT3:
|
|
|
|
case AbstractTextureFormat::DXT5:
|
|
|
|
case AbstractTextureFormat::BPTC:
|
|
|
|
return 16;
|
2018-01-21 06:59:19 -07:00
|
|
|
case AbstractTextureFormat::R16:
|
|
|
|
case AbstractTextureFormat::D16:
|
|
|
|
return 2;
|
2017-10-21 08:49:40 -06:00
|
|
|
case AbstractTextureFormat::RGBA8:
|
|
|
|
case AbstractTextureFormat::BGRA8:
|
2023-06-07 18:17:20 -06:00
|
|
|
case AbstractTextureFormat::RGB10_A2:
|
2018-07-16 21:22:48 -06:00
|
|
|
case AbstractTextureFormat::D24_S8:
|
2018-01-21 06:59:19 -07:00
|
|
|
case AbstractTextureFormat::R32F:
|
|
|
|
case AbstractTextureFormat::D32F:
|
2017-10-21 08:49:40 -06:00
|
|
|
return 4;
|
2018-01-21 06:59:19 -07:00
|
|
|
case AbstractTextureFormat::D32F_S8:
|
2023-06-07 18:17:20 -06:00
|
|
|
case AbstractTextureFormat::RGBA16F:
|
2018-01-21 06:59:19 -07:00
|
|
|
return 8;
|
2017-10-21 08:49:40 -06:00
|
|
|
default:
|
2020-11-13 20:33:26 -07:00
|
|
|
PanicAlertFmt("Unhandled texture format.");
|
2017-10-21 08:49:40 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-14 18:59:50 -07:00
|
|
|
u32 AbstractTexture::GetBlockSizeForFormat(AbstractTextureFormat format)
|
|
|
|
{
|
|
|
|
switch (format)
|
|
|
|
{
|
|
|
|
case AbstractTextureFormat::DXT1:
|
|
|
|
case AbstractTextureFormat::DXT3:
|
|
|
|
case AbstractTextureFormat::DXT5:
|
|
|
|
case AbstractTextureFormat::BPTC:
|
|
|
|
return 4;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-18 21:33:15 -06:00
|
|
|
const TextureConfig& AbstractTexture::GetConfig() const
|
2017-04-22 22:44:34 -06:00
|
|
|
{
|
|
|
|
return m_config;
|
|
|
|
}
|