2017-04-23 04:44:34 +00:00
|
|
|
// Copyright 2017 Dolphin Emulator Project
|
|
|
|
// Licensed under GPLv2+
|
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
2017-05-31 04:44:03 +00:00
|
|
|
#include "Common/Assert.h"
|
2017-09-09 05:24:41 +00:00
|
|
|
#include "Common/MsgHandler.h"
|
2017-10-30 12:00:15 +00:00
|
|
|
#include "VideoCommon/AbstractStagingTexture.h"
|
2017-04-23 04:44:34 +00:00
|
|
|
#include "VideoCommon/AbstractTexture.h"
|
2017-05-31 04:44:03 +00:00
|
|
|
#include "VideoCommon/ImageWrite.h"
|
2017-10-30 12:00:15 +00:00
|
|
|
#include "VideoCommon/RenderBase.h"
|
2017-04-23 04:44:34 +00:00
|
|
|
|
2017-11-19 06:23:19 +00:00
|
|
|
AbstractTexture::AbstractTexture(const TextureConfig& c) : m_config(c)
|
2017-04-23 04:44:34 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-02-15 01:59:50 +00:00
|
|
|
void AbstractTexture::FinishedRendering()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2017-04-23 04:44:34 +00:00
|
|
|
bool AbstractTexture::Save(const std::string& filename, unsigned int level)
|
|
|
|
{
|
2017-05-31 04:44:03 +00: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-15 00:34:35 +00:00
|
|
|
ASSERT(!IsCompressedFormat(m_config.format));
|
|
|
|
ASSERT(level < m_config.levels);
|
2017-05-31 04:44:03 +00:00
|
|
|
|
2017-10-30 12:00:15 +00: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-21 05:03:06 +00:00
|
|
|
TextureConfig readback_texture_config(level_width, level_height, 1, 1, 1,
|
2019-02-15 01:59:50 +00:00
|
|
|
AbstractTextureFormat::RGBA8, 0);
|
2017-10-30 12:00:15 +00:00
|
|
|
auto readback_texture =
|
|
|
|
g_renderer->CreateStagingTexture(StagingTextureType::Readback, readback_texture_config);
|
|
|
|
if (!readback_texture)
|
|
|
|
return false;
|
2017-05-31 04:44:03 +00:00
|
|
|
|
2017-10-30 12:00:15 +00: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-31 04:44:03 +00:00
|
|
|
return false;
|
|
|
|
|
2017-10-30 12:00:15 +00:00
|
|
|
return TextureToPng(reinterpret_cast<const u8*>(readback_texture->GetMappedPointer()),
|
|
|
|
static_cast<int>(readback_texture->GetMappedStride()), filename, level_width,
|
|
|
|
level_height);
|
2017-05-31 04:44:03 +00:00
|
|
|
}
|
|
|
|
|
2017-10-21 14:49:40 +00:00
|
|
|
bool AbstractTexture::IsCompressedFormat(AbstractTextureFormat format)
|
2017-04-23 04:44:34 +00:00
|
|
|
{
|
2017-09-09 05:24:41 +00:00
|
|
|
switch (format)
|
|
|
|
{
|
|
|
|
case AbstractTextureFormat::DXT1:
|
|
|
|
case AbstractTextureFormat::DXT3:
|
|
|
|
case AbstractTextureFormat::DXT5:
|
|
|
|
case AbstractTextureFormat::BPTC:
|
|
|
|
return true;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
2017-04-23 04:44:34 +00:00
|
|
|
}
|
|
|
|
|
2018-01-21 13:59:19 +00:00
|
|
|
bool AbstractTexture::IsDepthFormat(AbstractTextureFormat format)
|
|
|
|
{
|
|
|
|
switch (format)
|
|
|
|
{
|
|
|
|
case AbstractTextureFormat::D16:
|
2018-07-17 03:22:48 +00:00
|
|
|
case AbstractTextureFormat::D24_S8:
|
2018-01-21 13:59:19 +00:00
|
|
|
case AbstractTextureFormat::D32F:
|
|
|
|
case AbstractTextureFormat::D32F_S8:
|
|
|
|
return true;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-21 10:22:45 +00:00
|
|
|
bool AbstractTexture::IsStencilFormat(AbstractTextureFormat format)
|
|
|
|
{
|
2018-07-17 03:22:48 +00:00
|
|
|
return format == AbstractTextureFormat::D24_S8 || format == AbstractTextureFormat::D32F_S8;
|
2018-01-21 10:22:45 +00:00
|
|
|
}
|
|
|
|
|
2019-02-15 01:59:50 +00:00
|
|
|
AbstractTextureFormat AbstractTexture::GetColorFormatForDepthFormat(AbstractTextureFormat format)
|
|
|
|
{
|
|
|
|
switch (format)
|
|
|
|
{
|
|
|
|
case AbstractTextureFormat::D16:
|
|
|
|
return AbstractTextureFormat::R16;
|
|
|
|
|
|
|
|
case AbstractTextureFormat::D24_S8: // TODO: Incorrect
|
|
|
|
case AbstractTextureFormat::D32F:
|
|
|
|
case AbstractTextureFormat::D32F_S8:
|
|
|
|
return AbstractTextureFormat::R32F;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return format;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
u32 AbstractTexture::CalculateStrideForFormat(AbstractTextureFormat format, u32 row_length)
|
2017-04-23 04:44:34 +00:00
|
|
|
{
|
|
|
|
switch (format)
|
|
|
|
{
|
2017-06-12 17:37:28 +00:00
|
|
|
case AbstractTextureFormat::DXT1:
|
2017-04-23 04:44:34 +00:00
|
|
|
return static_cast<size_t>(std::max(1u, row_length / 4)) * 8;
|
2017-06-12 17:37:28 +00:00
|
|
|
case AbstractTextureFormat::DXT3:
|
|
|
|
case AbstractTextureFormat::DXT5:
|
2017-07-27 12:00:04 +00:00
|
|
|
case AbstractTextureFormat::BPTC:
|
2017-04-23 04:44:34 +00:00
|
|
|
return static_cast<size_t>(std::max(1u, row_length / 4)) * 16;
|
2018-01-21 13:59:19 +00:00
|
|
|
case AbstractTextureFormat::R16:
|
|
|
|
case AbstractTextureFormat::D16:
|
|
|
|
return static_cast<size_t>(row_length) * 2;
|
2017-06-12 17:37:28 +00:00
|
|
|
case AbstractTextureFormat::RGBA8:
|
2017-09-09 05:24:41 +00:00
|
|
|
case AbstractTextureFormat::BGRA8:
|
2018-01-21 13:59:19 +00:00
|
|
|
case AbstractTextureFormat::R32F:
|
|
|
|
case AbstractTextureFormat::D32F:
|
2018-07-17 03:22:48 +00:00
|
|
|
case AbstractTextureFormat::D24_S8:
|
2017-04-23 04:44:34 +00:00
|
|
|
return static_cast<size_t>(row_length) * 4;
|
2018-01-21 13:59:19 +00:00
|
|
|
case AbstractTextureFormat::D32F_S8:
|
|
|
|
return static_cast<size_t>(row_length) * 8;
|
2017-09-09 05:24:41 +00:00
|
|
|
default:
|
|
|
|
PanicAlert("Unhandled texture format.");
|
|
|
|
return 0;
|
2017-04-23 04:44:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-15 01:59:50 +00:00
|
|
|
u32 AbstractTexture::GetTexelSizeForFormat(AbstractTextureFormat format)
|
2017-10-21 14:49:40 +00:00
|
|
|
{
|
|
|
|
switch (format)
|
|
|
|
{
|
|
|
|
case AbstractTextureFormat::DXT1:
|
|
|
|
return 8;
|
|
|
|
case AbstractTextureFormat::DXT3:
|
|
|
|
case AbstractTextureFormat::DXT5:
|
|
|
|
case AbstractTextureFormat::BPTC:
|
|
|
|
return 16;
|
2018-01-21 13:59:19 +00:00
|
|
|
case AbstractTextureFormat::R16:
|
|
|
|
case AbstractTextureFormat::D16:
|
|
|
|
return 2;
|
2017-10-21 14:49:40 +00:00
|
|
|
case AbstractTextureFormat::RGBA8:
|
|
|
|
case AbstractTextureFormat::BGRA8:
|
2018-07-17 03:22:48 +00:00
|
|
|
case AbstractTextureFormat::D24_S8:
|
2018-01-21 13:59:19 +00:00
|
|
|
case AbstractTextureFormat::R32F:
|
|
|
|
case AbstractTextureFormat::D32F:
|
2017-10-21 14:49:40 +00:00
|
|
|
return 4;
|
2018-01-21 13:59:19 +00:00
|
|
|
case AbstractTextureFormat::D32F_S8:
|
|
|
|
return 8;
|
2017-10-21 14:49:40 +00:00
|
|
|
default:
|
|
|
|
PanicAlert("Unhandled texture format.");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-15 01:59:50 +00: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-19 03:33:15 +00:00
|
|
|
const TextureConfig& AbstractTexture::GetConfig() const
|
2017-04-23 04:44:34 +00:00
|
|
|
{
|
|
|
|
return m_config;
|
|
|
|
}
|