GPUDevice: Improve texture pooling
This commit is contained in:
parent
efaee4ab50
commit
dc5e4120cd
|
@ -405,10 +405,16 @@ void ImGuiManager::DrawPerformanceOverlay()
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_settings.display_show_gpu && g_gpu_device->IsGPUTimingEnabled())
|
if (g_settings.display_show_gpu)
|
||||||
{
|
{
|
||||||
text.assign("GPU: ");
|
if (g_gpu_device->IsGPUTimingEnabled())
|
||||||
FormatProcessorStat(text, System::GetGPUUsage(), System::GetGPUAverageTime());
|
{
|
||||||
|
text.assign("GPU: ");
|
||||||
|
FormatProcessorStat(text, System::GetGPUUsage(), System::GetGPUAverageTime());
|
||||||
|
DRAW_LINE(fixed_font, text, IM_COL32(255, 255, 255, 255));
|
||||||
|
}
|
||||||
|
|
||||||
|
text.format("VRAM: {} MB", (g_gpu_device->GetVRAMUsage() + (1048576 - 1)) / 1048576);
|
||||||
DRAW_LINE(fixed_font, text, IM_COL32(255, 255, 255, 255));
|
DRAW_LINE(fixed_font, text, IM_COL32(255, 255, 255, 255));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -182,6 +182,7 @@ void D3D11Device::SetFeatures(FeatureMask disabled_features)
|
||||||
m_features.gpu_timing = true;
|
m_features.gpu_timing = true;
|
||||||
m_features.shader_cache = true;
|
m_features.shader_cache = true;
|
||||||
m_features.pipeline_cache = false;
|
m_features.pipeline_cache = false;
|
||||||
|
m_features.prefer_unused_textures = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool D3D11Device::CreateSwapChain()
|
bool D3D11Device::CreateSwapChain()
|
||||||
|
|
|
@ -23,11 +23,7 @@ std::unique_ptr<GPUTexture> D3D11Device::CreateTexture(u32 width, u32 height, u3
|
||||||
GPUTexture::Type type, GPUTexture::Format format,
|
GPUTexture::Type type, GPUTexture::Format format,
|
||||||
const void* data, u32 data_stride)
|
const void* data, u32 data_stride)
|
||||||
{
|
{
|
||||||
std::unique_ptr<D3D11Texture> tex = std::make_unique<D3D11Texture>();
|
return D3D11Texture::Create(m_device.Get(), width, height, layers, levels, samples, type, format, data, data_stride);
|
||||||
if (!tex->Create(m_device.Get(), width, height, layers, levels, samples, type, format, data, data_stride))
|
|
||||||
tex.reset();
|
|
||||||
|
|
||||||
return tex;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool D3D11Device::DownloadTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, void* out_data,
|
bool D3D11Device::DownloadTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, void* out_data,
|
||||||
|
@ -154,11 +150,21 @@ std::unique_ptr<GPUSampler> D3D11Device::CreateSampler(const GPUSampler::Config&
|
||||||
return std::unique_ptr<GPUSampler>(new D3D11Sampler(std::move(ss)));
|
return std::unique_ptr<GPUSampler>(new D3D11Sampler(std::move(ss)));
|
||||||
}
|
}
|
||||||
|
|
||||||
D3D11Texture::D3D11Texture() = default;
|
D3D11Texture::D3D11Texture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, Type type, Format format,
|
||||||
|
ComPtr<ID3D11Texture2D> texture, ComPtr<ID3D11ShaderResourceView> srv,
|
||||||
|
ComPtr<ID3D11View> rtv_dsv)
|
||||||
|
: GPUTexture(static_cast<u16>(width), static_cast<u16>(height), static_cast<u8>(layers), static_cast<u8>(levels),
|
||||||
|
static_cast<u8>(samples), type, format),
|
||||||
|
m_texture(std::move(texture)), m_srv(std::move(srv)), m_rtv_dsv(std::move(rtv_dsv))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
D3D11Texture::~D3D11Texture()
|
D3D11Texture::~D3D11Texture()
|
||||||
{
|
{
|
||||||
Destroy();
|
D3D11Device::GetInstance().UnbindTexture(this);
|
||||||
|
m_rtv_dsv.Reset();
|
||||||
|
m_srv.Reset();
|
||||||
|
m_texture.Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
D3D11_TEXTURE2D_DESC D3D11Texture::GetDesc() const
|
D3D11_TEXTURE2D_DESC D3D11Texture::GetDesc() const
|
||||||
|
@ -191,11 +197,6 @@ void D3D11Texture::CommitClear(ID3D11DeviceContext1* context)
|
||||||
m_state = GPUTexture::State::Dirty;
|
m_state = GPUTexture::State::Dirty;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool D3D11Texture::IsValid() const
|
|
||||||
{
|
|
||||||
return static_cast<bool>(m_texture);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool D3D11Texture::Update(u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch, u32 layer /*= 0*/,
|
bool D3D11Texture::Update(u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch, u32 layer /*= 0*/,
|
||||||
u32 level /*= 0*/)
|
u32 level /*= 0*/)
|
||||||
{
|
{
|
||||||
|
@ -268,11 +269,13 @@ DXGI_FORMAT D3D11Texture::GetDXGIFormat() const
|
||||||
return D3DCommon::GetFormatMapping(m_format).resource_format;
|
return D3DCommon::GetFormatMapping(m_format).resource_format;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool D3D11Texture::Create(ID3D11Device* device, u32 width, u32 height, u32 layers, u32 levels, u32 samples, Type type,
|
std::unique_ptr<D3D11Texture> D3D11Texture::Create(ID3D11Device* device, u32 width, u32 height, u32 layers, u32 levels,
|
||||||
Format format, const void* initial_data /* = nullptr */, u32 initial_data_stride /* = 0 */)
|
u32 samples, Type type, Format format,
|
||||||
|
const void* initial_data /* = nullptr */,
|
||||||
|
u32 initial_data_stride /* = 0 */)
|
||||||
{
|
{
|
||||||
if (!ValidateConfig(width, height, layers, layers, samples, type, format))
|
if (!ValidateConfig(width, height, layers, layers, samples, type, format))
|
||||||
return false;
|
return nullptr;
|
||||||
|
|
||||||
u32 bind_flags = 0;
|
u32 bind_flags = 0;
|
||||||
D3D11_USAGE usage = D3D11_USAGE_DEFAULT;
|
D3D11_USAGE usage = D3D11_USAGE_DEFAULT;
|
||||||
|
@ -317,7 +320,7 @@ bool D3D11Texture::Create(ID3D11Device* device, u32 width, u32 height, u32 layer
|
||||||
Log_ErrorPrintf(
|
Log_ErrorPrintf(
|
||||||
"Create texture failed: 0x%08X (%ux%u levels:%u samples:%u format:%u bind_flags:%X initial_data:%p)", tex_hr,
|
"Create texture failed: 0x%08X (%ux%u levels:%u samples:%u format:%u bind_flags:%X initial_data:%p)", tex_hr,
|
||||||
width, height, levels, samples, static_cast<unsigned>(format), bind_flags, initial_data);
|
width, height, levels, samples, static_cast<unsigned>(format), bind_flags, initial_data);
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
ComPtr<ID3D11ShaderResourceView> srv;
|
ComPtr<ID3D11ShaderResourceView> srv;
|
||||||
|
@ -332,7 +335,7 @@ bool D3D11Texture::Create(ID3D11Device* device, u32 width, u32 height, u32 layer
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
{
|
{
|
||||||
Log_ErrorPrintf("Create SRV for texture failed: 0x%08X", hr);
|
Log_ErrorPrintf("Create SRV for texture failed: 0x%08X", hr);
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -347,7 +350,7 @@ bool D3D11Texture::Create(ID3D11Device* device, u32 width, u32 height, u32 layer
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
{
|
{
|
||||||
Log_ErrorPrintf("Create RTV for texture failed: 0x%08X", hr);
|
Log_ErrorPrintf("Create RTV for texture failed: 0x%08X", hr);
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
rtv_dsv = std::move(rtv);
|
rtv_dsv = std::move(rtv);
|
||||||
|
@ -362,32 +365,14 @@ bool D3D11Texture::Create(ID3D11Device* device, u32 width, u32 height, u32 layer
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
{
|
{
|
||||||
Log_ErrorPrintf("Create DSV for texture failed: 0x%08X", hr);
|
Log_ErrorPrintf("Create DSV for texture failed: 0x%08X", hr);
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
rtv_dsv = std::move(dsv);
|
rtv_dsv = std::move(dsv);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_texture = std::move(texture);
|
return std::unique_ptr<D3D11Texture>(new D3D11Texture(width, height, layers, levels, samples, type, format,
|
||||||
m_srv = std::move(srv);
|
std::move(texture), std::move(srv), std::move(rtv_dsv)));
|
||||||
m_rtv_dsv = std::move(rtv_dsv);
|
|
||||||
m_width = static_cast<u16>(width);
|
|
||||||
m_height = static_cast<u16>(height);
|
|
||||||
m_layers = static_cast<u8>(layers);
|
|
||||||
m_levels = static_cast<u8>(levels);
|
|
||||||
m_samples = static_cast<u8>(samples);
|
|
||||||
m_type = type;
|
|
||||||
m_format = format;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void D3D11Texture::Destroy()
|
|
||||||
{
|
|
||||||
D3D11Device::GetInstance().UnbindTexture(this);
|
|
||||||
m_rtv_dsv.Reset();
|
|
||||||
m_srv.Reset();
|
|
||||||
m_texture.Reset();
|
|
||||||
ClearBaseProperties();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
D3D11TextureBuffer::D3D11TextureBuffer(Format format, u32 size_in_elements) : GPUTextureBuffer(format, size_in_elements)
|
D3D11TextureBuffer::D3D11TextureBuffer(Format format, u32 size_in_elements) : GPUTextureBuffer(format, size_in_elements)
|
||||||
|
|
|
@ -42,7 +42,6 @@ public:
|
||||||
template<typename T>
|
template<typename T>
|
||||||
using ComPtr = Microsoft::WRL::ComPtr<T>;
|
using ComPtr = Microsoft::WRL::ComPtr<T>;
|
||||||
|
|
||||||
D3D11Texture();
|
|
||||||
~D3D11Texture();
|
~D3D11Texture();
|
||||||
|
|
||||||
ALWAYS_INLINE ID3D11Texture2D* GetD3DTexture() const { return m_texture.Get(); }
|
ALWAYS_INLINE ID3D11Texture2D* GetD3DTexture() const { return m_texture.Get(); }
|
||||||
|
@ -75,16 +74,13 @@ public:
|
||||||
}
|
}
|
||||||
ALWAYS_INLINE operator bool() const { return static_cast<bool>(m_texture); }
|
ALWAYS_INLINE operator bool() const { return static_cast<bool>(m_texture); }
|
||||||
|
|
||||||
bool Create(ID3D11Device* device, u32 width, u32 height, u32 layers, u32 levels, u32 samples, Type type,
|
static std::unique_ptr<D3D11Texture> Create(ID3D11Device* device, u32 width, u32 height, u32 layers, u32 levels,
|
||||||
Format format, const void* initial_data = nullptr, u32 initial_data_stride = 0);
|
u32 samples, Type type, Format format, const void* initial_data = nullptr,
|
||||||
|
u32 initial_data_stride = 0);
|
||||||
void Destroy();
|
|
||||||
|
|
||||||
D3D11_TEXTURE2D_DESC GetDesc() const;
|
D3D11_TEXTURE2D_DESC GetDesc() const;
|
||||||
void CommitClear(ID3D11DeviceContext1* context);
|
void CommitClear(ID3D11DeviceContext1* context);
|
||||||
|
|
||||||
bool IsValid() const override;
|
|
||||||
|
|
||||||
bool Update(u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch, u32 layer = 0, u32 level = 0) override;
|
bool Update(u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch, u32 layer = 0, u32 level = 0) override;
|
||||||
bool Map(void** map, u32* map_stride, u32 x, u32 y, u32 width, u32 height, u32 layer = 0, u32 level = 0) override;
|
bool Map(void** map, u32* map_stride, u32 x, u32 y, u32 width, u32 height, u32 layer = 0, u32 level = 0) override;
|
||||||
void Unmap() override;
|
void Unmap() override;
|
||||||
|
@ -92,6 +88,9 @@ public:
|
||||||
void SetDebugName(const std::string_view& name) override;
|
void SetDebugName(const std::string_view& name) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
D3D11Texture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, Type type, Format format,
|
||||||
|
ComPtr<ID3D11Texture2D> texture, ComPtr<ID3D11ShaderResourceView> srv, ComPtr<ID3D11View> rtv_dsv);
|
||||||
|
|
||||||
ComPtr<ID3D11Texture2D> m_texture;
|
ComPtr<ID3D11Texture2D> m_texture;
|
||||||
ComPtr<ID3D11ShaderResourceView> m_srv;
|
ComPtr<ID3D11ShaderResourceView> m_srv;
|
||||||
ComPtr<ID3D11View> m_rtv_dsv;
|
ComPtr<ID3D11View> m_rtv_dsv;
|
||||||
|
|
|
@ -1187,6 +1187,7 @@ void D3D12Device::SetFeatures(FeatureMask disabled_features)
|
||||||
m_features.gpu_timing = true;
|
m_features.gpu_timing = true;
|
||||||
m_features.shader_cache = true;
|
m_features.shader_cache = true;
|
||||||
m_features.pipeline_cache = true;
|
m_features.pipeline_cache = true;
|
||||||
|
m_features.prefer_unused_textures = true;
|
||||||
|
|
||||||
BOOL allow_tearing_supported = false;
|
BOOL allow_tearing_supported = false;
|
||||||
HRESULT hr = m_dxgi_factory->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allow_tearing_supported,
|
HRESULT hr = m_dxgi_factory->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allow_tearing_supported,
|
||||||
|
|
|
@ -37,7 +37,6 @@ public:
|
||||||
ALWAYS_INLINE DXGI_FORMAT GetDXGIFormat() const { return m_dxgi_format; }
|
ALWAYS_INLINE DXGI_FORMAT GetDXGIFormat() const { return m_dxgi_format; }
|
||||||
ALWAYS_INLINE ID3D12Resource* GetResource() const { return m_resource.Get(); }
|
ALWAYS_INLINE ID3D12Resource* GetResource() const { return m_resource.Get(); }
|
||||||
|
|
||||||
bool IsValid() const override { return static_cast<bool>(m_resource); }
|
|
||||||
bool Update(u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch, u32 layer = 0, u32 level = 0) override;
|
bool Update(u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch, u32 layer = 0, u32 level = 0) override;
|
||||||
bool Map(void** map, u32* map_stride, u32 x, u32 y, u32 width, u32 height, u32 layer = 0, u32 level = 0) override;
|
bool Map(void** map, u32* map_stride, u32 x, u32 y, u32 width, u32 height, u32 layer = 0, u32 level = 0) override;
|
||||||
void Unmap() override;
|
void Unmap() override;
|
||||||
|
|
|
@ -38,6 +38,7 @@ Log_SetChannel(GPUDevice);
|
||||||
std::unique_ptr<GPUDevice> g_gpu_device;
|
std::unique_ptr<GPUDevice> g_gpu_device;
|
||||||
|
|
||||||
static std::string s_pipeline_cache_path;
|
static std::string s_pipeline_cache_path;
|
||||||
|
size_t GPUDevice::s_total_vram_usage = 0;
|
||||||
|
|
||||||
GPUSampler::GPUSampler() = default;
|
GPUSampler::GPUSampler() = default;
|
||||||
|
|
||||||
|
@ -763,6 +764,11 @@ Common::Rectangle<s32> GPUDevice::FlipToLowerLeft(const Common::Rectangle<s32>&
|
||||||
return Common::Rectangle<s32>(rc.left, flipped_y, rc.right, flipped_y + height);
|
return Common::Rectangle<s32>(rc.left, flipped_y, rc.right, flipped_y + height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GPUDevice::IsTexturePoolType(GPUTexture::Type type)
|
||||||
|
{
|
||||||
|
return (type == GPUTexture::Type::Texture || type == GPUTexture::Type::DynamicTexture);
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<GPUTexture> GPUDevice::FetchTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
std::unique_ptr<GPUTexture> GPUDevice::FetchTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||||
GPUTexture::Type type, GPUTexture::Format format,
|
GPUTexture::Type type, GPUTexture::Format format,
|
||||||
const void* data /*= nullptr*/, u32 data_stride /*= 0*/)
|
const void* data /*= nullptr*/, u32 data_stride /*= 0*/)
|
||||||
|
@ -778,21 +784,56 @@ std::unique_ptr<GPUTexture> GPUDevice::FetchTexture(u32 width, u32 height, u32 l
|
||||||
format,
|
format,
|
||||||
0u};
|
0u};
|
||||||
|
|
||||||
for (auto it = m_texture_pool.begin(); it != m_texture_pool.end(); ++it)
|
const bool is_texture = IsTexturePoolType(type);
|
||||||
|
TexturePool& pool = is_texture ? m_texture_pool : m_target_pool;
|
||||||
|
const u32 pool_size = (is_texture ? MAX_TEXTURE_POOL_SIZE : MAX_TARGET_POOL_SIZE);
|
||||||
|
|
||||||
|
TexturePool::iterator it;
|
||||||
|
|
||||||
|
if (is_texture && m_features.prefer_unused_textures)
|
||||||
{
|
{
|
||||||
if (it->key == key)
|
// Try to find a texture that wasn't used this frame first.
|
||||||
|
// Start at the back of the pool.
|
||||||
|
it = m_texture_pool.end();
|
||||||
|
for (auto rit = m_texture_pool.rbegin(); rit != m_texture_pool.rend(); ++rit)
|
||||||
{
|
{
|
||||||
if (data && !it->texture->Update(0, 0, width, height, data, data_stride, 0, 0))
|
if (rit->use_counter == m_texture_pool_counter)
|
||||||
{
|
{
|
||||||
// This shouldn't happen...
|
// We're into textures recycled this frame, not going to find anything newer.
|
||||||
Log_ErrorFmt("Failed to upload {}x{} to pooled texture", width, height);
|
// But prefer reuse over creating a new texture.
|
||||||
break;
|
if (m_texture_pool.size() < pool_size)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (rit->key == key)
|
||||||
|
{
|
||||||
|
it = std::prev(rit.base());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (it = pool.begin(); it != pool.end(); ++it)
|
||||||
|
{
|
||||||
|
if (it->key == key)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it != pool.end())
|
||||||
|
{
|
||||||
|
if (!data || it->texture->Update(0, 0, width, height, data, data_stride, 0, 0))
|
||||||
|
{
|
||||||
ret = std::move(it->texture);
|
ret = std::move(it->texture);
|
||||||
m_texture_pool.erase(it);
|
m_texture_pool.erase(it);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// This shouldn't happen...
|
||||||
|
Log_ErrorFmt("Failed to upload {}x{} to pooled texture", width, height);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = CreateTexture(width, height, layers, levels, samples, type, format, data, data_stride);
|
ret = CreateTexture(width, height, layers, levels, samples, type, format, data, data_stride);
|
||||||
|
@ -814,23 +855,6 @@ void GPUDevice::RecycleTexture(std::unique_ptr<GPUTexture> texture)
|
||||||
if (!texture)
|
if (!texture)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
u32 remove_count = m_texture_pool_counter + POOL_PURGE_DELAY;
|
|
||||||
if (remove_count < m_texture_pool_counter)
|
|
||||||
{
|
|
||||||
// wrapped around, handle it
|
|
||||||
if (m_texture_pool.empty())
|
|
||||||
{
|
|
||||||
m_texture_pool_counter = 0;
|
|
||||||
remove_count = POOL_PURGE_DELAY;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const u32 reduce = m_texture_pool.front().remove_count;
|
|
||||||
m_texture_pool_counter -= reduce;
|
|
||||||
remove_count -= reduce;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const TexturePoolKey key = {static_cast<u16>(texture->GetWidth()),
|
const TexturePoolKey key = {static_cast<u16>(texture->GetWidth()),
|
||||||
static_cast<u16>(texture->GetHeight()),
|
static_cast<u16>(texture->GetHeight()),
|
||||||
static_cast<u8>(texture->GetLayers()),
|
static_cast<u8>(texture->GetLayers()),
|
||||||
|
@ -840,28 +864,74 @@ void GPUDevice::RecycleTexture(std::unique_ptr<GPUTexture> texture)
|
||||||
texture->GetFormat(),
|
texture->GetFormat(),
|
||||||
0u};
|
0u};
|
||||||
|
|
||||||
m_texture_pool.push_back({std::move(texture), remove_count, key});
|
const bool is_texture = IsTexturePoolType(texture->GetType());
|
||||||
|
TexturePool& pool = is_texture ? m_texture_pool : m_target_pool;
|
||||||
|
pool.push_back({std::move(texture), m_texture_pool_counter, key});
|
||||||
|
|
||||||
|
const u32 max_size = is_texture ? MAX_TEXTURE_POOL_SIZE : MAX_TARGET_POOL_SIZE;
|
||||||
|
while (pool.size() >= max_size)
|
||||||
|
{
|
||||||
|
Log_ProfileFmt("Trim {}x{} texture from pool", pool.front().texture->GetWidth(), pool.front().texture->GetHeight());
|
||||||
|
pool.pop_front();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPUDevice::PurgeTexturePool()
|
void GPUDevice::PurgeTexturePool()
|
||||||
{
|
{
|
||||||
m_texture_pool_counter = 0;
|
m_texture_pool_counter = 0;
|
||||||
m_texture_pool.clear();
|
m_texture_pool.clear();
|
||||||
|
m_target_pool.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPUDevice::TrimTexturePool()
|
void GPUDevice::TrimTexturePool()
|
||||||
{
|
{
|
||||||
if (m_texture_pool.empty())
|
GL_INS_FMT("Texture Pool Size: {}", m_texture_pool.size());
|
||||||
|
GL_INS_FMT("Target Pool Size: {}", m_target_pool.size());
|
||||||
|
GL_INS_FMT("VRAM Usage: {:.2f} MB", s_total_vram_usage / 1048576.0);
|
||||||
|
|
||||||
|
Log_DebugFmt("Texture Pool Size: {} Target Pool Size: {} VRAM: {:.2f} MB", m_texture_pool.size(),
|
||||||
|
m_target_pool.size(), s_total_vram_usage / 1048756.0);
|
||||||
|
|
||||||
|
if (m_texture_pool.empty() && m_target_pool.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const u32 counter = m_texture_pool_counter++;
|
const u32 prev_counter = m_texture_pool_counter++;
|
||||||
for (auto it = m_texture_pool.begin(); it != m_texture_pool.end();)
|
for (u32 pool_idx = 0; pool_idx < 2; pool_idx++)
|
||||||
{
|
{
|
||||||
if (counter < it->remove_count)
|
TexturePool& pool = pool_idx ? m_target_pool : m_texture_pool;
|
||||||
break;
|
for (auto it = pool.begin(); it != pool.end();)
|
||||||
|
{
|
||||||
|
const u32 delta = (it->use_counter - prev_counter);
|
||||||
|
if (delta < POOL_PURGE_DELAY)
|
||||||
|
break;
|
||||||
|
|
||||||
Log_ProfileFmt("Trim {}x{} texture from pool", it->texture->GetWidth(), it->texture->GetHeight());
|
Log_ProfileFmt("Trim {}x{} texture from pool", it->texture->GetWidth(), it->texture->GetHeight());
|
||||||
it = m_texture_pool.erase(it);
|
it = pool.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_texture_pool_counter < prev_counter) [[unlikely]]
|
||||||
|
{
|
||||||
|
// wrapped around, handle it
|
||||||
|
if (m_texture_pool.empty() && m_target_pool.empty())
|
||||||
|
{
|
||||||
|
m_texture_pool_counter = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const u32 texture_min =
|
||||||
|
m_texture_pool.empty() ? std::numeric_limits<u32>::max() : m_texture_pool.front().use_counter;
|
||||||
|
const u32 target_min =
|
||||||
|
m_target_pool.empty() ? std::numeric_limits<u32>::max() : m_target_pool.front().use_counter;
|
||||||
|
const u32 reduce = std::min(texture_min, target_min);
|
||||||
|
m_texture_pool_counter -= reduce;
|
||||||
|
for (u32 pool_idx = 0; pool_idx < 2; pool_idx++)
|
||||||
|
{
|
||||||
|
TexturePool& pool = pool_idx ? m_target_pool : m_texture_pool;
|
||||||
|
for (TexturePoolEntry& entry : pool)
|
||||||
|
entry.use_counter -= reduce;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -424,6 +424,8 @@ protected:
|
||||||
class GPUDevice
|
class GPUDevice
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
friend GPUTexture;
|
||||||
|
|
||||||
// TODO: drop virtuals
|
// TODO: drop virtuals
|
||||||
// TODO: gpu crash handling on present
|
// TODO: gpu crash handling on present
|
||||||
using DrawIndex = u16;
|
using DrawIndex = u16;
|
||||||
|
@ -451,6 +453,7 @@ public:
|
||||||
bool gpu_timing : 1;
|
bool gpu_timing : 1;
|
||||||
bool shader_cache : 1;
|
bool shader_cache : 1;
|
||||||
bool pipeline_cache : 1;
|
bool pipeline_cache : 1;
|
||||||
|
bool prefer_unused_textures : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AdapterAndModeList
|
struct AdapterAndModeList
|
||||||
|
@ -627,6 +630,7 @@ public:
|
||||||
virtual void SetVSync(bool enabled) = 0;
|
virtual void SetVSync(bool enabled) = 0;
|
||||||
|
|
||||||
ALWAYS_INLINE bool IsDebugDevice() const { return m_debug_device; }
|
ALWAYS_INLINE bool IsDebugDevice() const { return m_debug_device; }
|
||||||
|
ALWAYS_INLINE size_t GetVRAMUsage() const { return s_total_vram_usage; }
|
||||||
|
|
||||||
bool UpdateImGuiFontTexture();
|
bool UpdateImGuiFontTexture();
|
||||||
bool UsesLowerLeftOrigin() const;
|
bool UsesLowerLeftOrigin() const;
|
||||||
|
@ -675,7 +679,9 @@ protected:
|
||||||
std::unique_ptr<GPUSampler> m_linear_sampler;
|
std::unique_ptr<GPUSampler> m_linear_sampler;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr u32 POOL_PURGE_DELAY = 60;
|
static constexpr u32 MAX_TEXTURE_POOL_SIZE = 100;
|
||||||
|
static constexpr u32 MAX_TARGET_POOL_SIZE = 50;
|
||||||
|
static constexpr u32 POOL_PURGE_DELAY = 300;
|
||||||
|
|
||||||
struct TexturePoolKey
|
struct TexturePoolKey
|
||||||
{
|
{
|
||||||
|
@ -700,19 +706,27 @@ private:
|
||||||
struct TexturePoolEntry
|
struct TexturePoolEntry
|
||||||
{
|
{
|
||||||
std::unique_ptr<GPUTexture> texture;
|
std::unique_ptr<GPUTexture> texture;
|
||||||
u32 remove_count;
|
u32 use_counter;
|
||||||
TexturePoolKey key;
|
TexturePoolKey key;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using TexturePool = std::deque<TexturePoolEntry>;
|
||||||
|
|
||||||
void OpenShaderCache(const std::string_view& base_path, u32 version);
|
void OpenShaderCache(const std::string_view& base_path, u32 version);
|
||||||
void CloseShaderCache();
|
void CloseShaderCache();
|
||||||
bool CreateResources();
|
bool CreateResources();
|
||||||
void DestroyResources();
|
void DestroyResources();
|
||||||
|
|
||||||
|
static bool IsTexturePoolType(GPUTexture::Type type);
|
||||||
|
|
||||||
|
static size_t s_total_vram_usage;
|
||||||
|
|
||||||
std::unique_ptr<GPUPipeline> m_imgui_pipeline;
|
std::unique_ptr<GPUPipeline> m_imgui_pipeline;
|
||||||
std::unique_ptr<GPUTexture> m_imgui_font_texture;
|
std::unique_ptr<GPUTexture> m_imgui_font_texture;
|
||||||
|
|
||||||
std::deque<TexturePoolEntry> m_texture_pool;
|
TexturePool m_texture_pool;
|
||||||
|
TexturePool m_target_pool;
|
||||||
|
size_t m_pool_vram_usage = 0;
|
||||||
u32 m_texture_pool_counter = 0;
|
u32 m_texture_pool_counter = 0;
|
||||||
|
|
||||||
// TODO: Move out.
|
// TODO: Move out.
|
||||||
|
|
|
@ -10,15 +10,17 @@
|
||||||
|
|
||||||
Log_SetChannel(GPUTexture);
|
Log_SetChannel(GPUTexture);
|
||||||
|
|
||||||
GPUTexture::GPUTexture() = default;
|
|
||||||
|
|
||||||
GPUTexture::GPUTexture(u16 width, u16 height, u8 layers, u8 levels, u8 samples, Type type, Format format)
|
GPUTexture::GPUTexture(u16 width, u16 height, u8 layers, u8 levels, u8 samples, Type type, Format format)
|
||||||
: m_width(width), m_height(height), m_layers(layers), m_levels(levels), m_samples(samples), m_type(type),
|
: m_width(width), m_height(height), m_layers(layers), m_levels(levels), m_samples(samples), m_type(type),
|
||||||
m_format(format)
|
m_format(format)
|
||||||
{
|
{
|
||||||
|
GPUDevice::s_total_vram_usage += GetVRAMUsage();
|
||||||
}
|
}
|
||||||
|
|
||||||
GPUTexture::~GPUTexture() = default;
|
GPUTexture::~GPUTexture()
|
||||||
|
{
|
||||||
|
GPUDevice::s_total_vram_usage -= GetVRAMUsage();
|
||||||
|
}
|
||||||
|
|
||||||
const char* GPUTexture::GetFormatName(Format format)
|
const char* GPUTexture::GetFormatName(Format format)
|
||||||
{
|
{
|
||||||
|
@ -48,23 +50,30 @@ const char* GPUTexture::GetFormatName(Format format)
|
||||||
return format_names[static_cast<u8>(format)];
|
return format_names[static_cast<u8>(format)];
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPUTexture::ClearBaseProperties()
|
|
||||||
{
|
|
||||||
m_width = 0;
|
|
||||||
m_height = 0;
|
|
||||||
m_layers = 0;
|
|
||||||
m_levels = 0;
|
|
||||||
m_samples = 0;
|
|
||||||
m_type = GPUTexture::Type::Unknown;
|
|
||||||
m_format = GPUTexture::Format::Unknown;
|
|
||||||
m_state = State::Dirty;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::array<float, 4> GPUTexture::GetUNormClearColor() const
|
std::array<float, 4> GPUTexture::GetUNormClearColor() const
|
||||||
{
|
{
|
||||||
return GPUDevice::RGBA8ToFloat(m_clear_value.color);
|
return GPUDevice::RGBA8ToFloat(m_clear_value.color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t GPUTexture::GetVRAMUsage() const
|
||||||
|
{
|
||||||
|
if (m_levels == 1) [[likely]]
|
||||||
|
return ((static_cast<size_t>(m_width * m_height) * GetPixelSize(m_format)) * m_layers * m_samples);
|
||||||
|
|
||||||
|
const size_t ps = GetPixelSize(m_format) * m_layers * m_samples;
|
||||||
|
u32 width = m_width;
|
||||||
|
u32 height = m_height;
|
||||||
|
size_t ts = 0;
|
||||||
|
for (u32 i = 0; i < m_levels; i++)
|
||||||
|
{
|
||||||
|
width = (width > 1) ? (width / 2) : width;
|
||||||
|
height = (height > 1) ? (height / 2) : height;
|
||||||
|
ts += static_cast<size_t>(width * height) * ps;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ts;
|
||||||
|
}
|
||||||
|
|
||||||
u32 GPUTexture::GetPixelSize(GPUTexture::Format format)
|
u32 GPUTexture::GetPixelSize(GPUTexture::Format format)
|
||||||
{
|
{
|
||||||
static constexpr std::array<u8, static_cast<size_t>(Format::MaxCount)> sizes = {{
|
static constexpr std::array<u8, static_cast<size_t>(Format::MaxCount)> sizes = {{
|
||||||
|
|
|
@ -73,9 +73,18 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
GPUTexture(const GPUTexture&) = delete;
|
||||||
virtual ~GPUTexture();
|
virtual ~GPUTexture();
|
||||||
|
|
||||||
static const char* GetFormatName(Format format);
|
static const char* GetFormatName(Format format);
|
||||||
|
static u32 GetPixelSize(GPUTexture::Format format);
|
||||||
|
static bool IsDepthFormat(GPUTexture::Format format);
|
||||||
|
static bool IsDepthStencilFormat(GPUTexture::Format format);
|
||||||
|
static bool ValidateConfig(u32 width, u32 height, u32 layers, u32 levels, u32 samples, Type type, Format format);
|
||||||
|
|
||||||
|
static bool ConvertTextureDataToRGBA8(u32 width, u32 height, std::vector<u32>& texture_data, u32& texture_data_stride,
|
||||||
|
GPUTexture::Format format);
|
||||||
|
static void FlipTextureDataRGBA8(u32 width, u32 height, std::vector<u32>& texture_data, u32 texture_data_stride);
|
||||||
|
|
||||||
ALWAYS_INLINE u32 GetWidth() const { return m_width; }
|
ALWAYS_INLINE u32 GetWidth() const { return m_width; }
|
||||||
ALWAYS_INLINE u32 GetHeight() const { return m_height; }
|
ALWAYS_INLINE u32 GetHeight() const { return m_height; }
|
||||||
|
@ -122,16 +131,9 @@ public:
|
||||||
m_clear_value.depth = depth;
|
m_clear_value.depth = depth;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 GetPixelSize(GPUTexture::Format format);
|
size_t GetVRAMUsage() const;
|
||||||
static bool IsDepthFormat(GPUTexture::Format format);
|
|
||||||
static bool IsDepthStencilFormat(GPUTexture::Format format);
|
|
||||||
static bool ValidateConfig(u32 width, u32 height, u32 layers, u32 levels, u32 samples, Type type, Format format);
|
|
||||||
|
|
||||||
static bool ConvertTextureDataToRGBA8(u32 width, u32 height, std::vector<u32>& texture_data, u32& texture_data_stride,
|
GPUTexture& operator=(const GPUTexture&) = delete;
|
||||||
GPUTexture::Format format);
|
|
||||||
static void FlipTextureDataRGBA8(u32 width, u32 height, std::vector<u32>& texture_data, u32 texture_data_stride);
|
|
||||||
|
|
||||||
virtual bool IsValid() const = 0;
|
|
||||||
|
|
||||||
virtual bool Update(u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch, u32 layer = 0,
|
virtual bool Update(u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch, u32 layer = 0,
|
||||||
u32 level = 0) = 0;
|
u32 level = 0) = 0;
|
||||||
|
@ -144,11 +146,8 @@ public:
|
||||||
virtual void SetDebugName(const std::string_view& name) = 0;
|
virtual void SetDebugName(const std::string_view& name) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
GPUTexture();
|
|
||||||
GPUTexture(u16 width, u16 height, u8 layers, u8 levels, u8 samples, Type type, Format format);
|
GPUTexture(u16 width, u16 height, u8 layers, u8 levels, u8 samples, Type type, Format format);
|
||||||
|
|
||||||
void ClearBaseProperties();
|
|
||||||
|
|
||||||
u16 m_width = 0;
|
u16 m_width = 0;
|
||||||
u16 m_height = 0;
|
u16 m_height = 0;
|
||||||
u8 m_layers = 0;
|
u8 m_layers = 0;
|
||||||
|
|
|
@ -107,9 +107,6 @@ public:
|
||||||
|
|
||||||
bool Create(id<MTLDevice> device, u32 width, u32 height, u32 layers, u32 levels, u32 samples, Type type,
|
bool Create(id<MTLDevice> device, u32 width, u32 height, u32 layers, u32 levels, u32 samples, Type type,
|
||||||
Format format, const void* initial_data = nullptr, u32 initial_data_stride = 0);
|
Format format, const void* initial_data = nullptr, u32 initial_data_stride = 0);
|
||||||
void Destroy();
|
|
||||||
|
|
||||||
bool IsValid() const override;
|
|
||||||
|
|
||||||
bool Update(u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch, u32 layer = 0, u32 level = 0) override;
|
bool Update(u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch, u32 layer = 0, u32 level = 0) override;
|
||||||
bool Map(void** map, u32* map_stride, u32 x, u32 y, u32 width, u32 height, u32 layer = 0, u32 level = 0) override;
|
bool Map(void** map, u32* map_stride, u32 x, u32 y, u32 width, u32 height, u32 layer = 0, u32 level = 0) override;
|
||||||
|
|
|
@ -220,6 +220,7 @@ void MetalDevice::SetFeatures(FeatureMask disabled_features)
|
||||||
m_features.partial_msaa_resolve = false;
|
m_features.partial_msaa_resolve = false;
|
||||||
m_features.shader_cache = true;
|
m_features.shader_cache = true;
|
||||||
m_features.pipeline_cache = false;
|
m_features.pipeline_cache = false;
|
||||||
|
m_features.prefer_unused_textures = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MetalDevice::LoadShaders()
|
bool MetalDevice::LoadShaders()
|
||||||
|
@ -871,13 +872,11 @@ MetalTexture::MetalTexture(id<MTLTexture> texture, u16 width, u16 height, u8 lay
|
||||||
|
|
||||||
MetalTexture::~MetalTexture()
|
MetalTexture::~MetalTexture()
|
||||||
{
|
{
|
||||||
MetalDevice::GetInstance().UnbindTexture(this);
|
if (m_texture != nil)
|
||||||
Destroy();
|
{
|
||||||
}
|
MetalDevice::GetInstance().UnbindTexture(this);
|
||||||
|
MetalDevice::DeferRelease(m_texture);
|
||||||
bool MetalTexture::IsValid() const
|
}
|
||||||
{
|
|
||||||
return (m_texture != nil);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MetalTexture::Update(u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch, u32 layer /*= 0*/,
|
bool MetalTexture::Update(u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch, u32 layer /*= 0*/,
|
||||||
|
@ -1029,16 +1028,6 @@ void MetalTexture::SetDebugName(const std::string_view& name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetalTexture::Destroy()
|
|
||||||
{
|
|
||||||
if (m_texture != nil)
|
|
||||||
{
|
|
||||||
MetalDevice::DeferRelease(m_texture);
|
|
||||||
m_texture = nil;
|
|
||||||
}
|
|
||||||
ClearBaseProperties();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<GPUTexture> MetalDevice::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
std::unique_ptr<GPUTexture> MetalDevice::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||||
GPUTexture::Type type, GPUTexture::Format format,
|
GPUTexture::Type type, GPUTexture::Format format,
|
||||||
const void* data, u32 data_stride)
|
const void* data, u32 data_stride)
|
||||||
|
|
|
@ -52,11 +52,7 @@ std::unique_ptr<GPUTexture> OpenGLDevice::CreateTexture(u32 width, u32 height, u
|
||||||
GPUTexture::Type type, GPUTexture::Format format,
|
GPUTexture::Type type, GPUTexture::Format format,
|
||||||
const void* data, u32 data_stride)
|
const void* data, u32 data_stride)
|
||||||
{
|
{
|
||||||
std::unique_ptr<OpenGLTexture> tex(std::make_unique<OpenGLTexture>());
|
return OpenGLTexture::Create(width, height, layers, levels, samples, type, format, data, data_stride);
|
||||||
if (!tex->Create(width, height, layers, levels, samples, type, format, data, data_stride))
|
|
||||||
tex.reset();
|
|
||||||
|
|
||||||
return tex;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OpenGLDevice::DownloadTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, void* out_data,
|
bool OpenGLDevice::DownloadTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, void* out_data,
|
||||||
|
@ -533,6 +529,9 @@ bool OpenGLDevice::CheckFeatures(bool* buggy_pbo, FeatureMask disabled_features)
|
||||||
"startup will be slow due to compiling shaders.");
|
"startup will be slow due to compiling shaders.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mobile drivers prefer textures to not be updated mid-frame.
|
||||||
|
m_features.prefer_unused_textures = is_gles || vendor_id_arm || vendor_id_powervr || vendor_id_qualcomm;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -82,11 +82,22 @@ const std::tuple<GLenum, GLenum, GLenum>& OpenGLTexture::GetPixelFormatMapping(G
|
||||||
return gles ? mapping_gles[static_cast<u32>(format)] : mapping[static_cast<u32>(format)];
|
return gles ? mapping_gles[static_cast<u32>(format)] : mapping[static_cast<u32>(format)];
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenGLTexture::OpenGLTexture() = default;
|
OpenGLTexture::OpenGLTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, Type type, Format format,
|
||||||
|
GLuint id)
|
||||||
|
: GPUTexture(static_cast<u16>(width), static_cast<u16>(height), static_cast<u8>(layers), static_cast<u8>(levels),
|
||||||
|
static_cast<u8>(samples), type, format),
|
||||||
|
m_id(id)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
OpenGLTexture::~OpenGLTexture()
|
OpenGLTexture::~OpenGLTexture()
|
||||||
{
|
{
|
||||||
Destroy();
|
if (m_id != 0)
|
||||||
|
{
|
||||||
|
OpenGLDevice::GetInstance().UnbindTexture(this);
|
||||||
|
glDeleteTextures(1, &m_id);
|
||||||
|
m_id = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OpenGLTexture::UseTextureStorage(bool multisampled)
|
bool OpenGLTexture::UseTextureStorage(bool multisampled)
|
||||||
|
@ -99,16 +110,16 @@ bool OpenGLTexture::UseTextureStorage() const
|
||||||
return UseTextureStorage(IsMultisampled());
|
return UseTextureStorage(IsMultisampled());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OpenGLTexture::Create(u32 width, u32 height, u32 layers, u32 levels, u32 samples, Type type, Format format,
|
std::unique_ptr<OpenGLTexture> OpenGLTexture::Create(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||||
const void* data, u32 data_pitch)
|
Type type, Format format, const void* data, u32 data_pitch)
|
||||||
{
|
{
|
||||||
if (!ValidateConfig(width, height, layers, levels, samples, type, format))
|
if (!ValidateConfig(width, height, layers, levels, samples, type, format))
|
||||||
return false;
|
return nullptr;
|
||||||
|
|
||||||
if (layers > 1 && data)
|
if (layers > 1 && data)
|
||||||
{
|
{
|
||||||
Log_ErrorPrintf("Loading texture array data not currently supported");
|
Log_ErrorPrintf("Loading texture array data not currently supported");
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const GLenum target =
|
const GLenum target =
|
||||||
|
@ -211,34 +222,10 @@ bool OpenGLTexture::Create(u32 width, u32 height, u32 layers, u32 levels, u32 sa
|
||||||
{
|
{
|
||||||
Log_ErrorPrintf("Failed to create texture: 0x%X", error);
|
Log_ErrorPrintf("Failed to create texture: 0x%X", error);
|
||||||
glDeleteTextures(1, &id);
|
glDeleteTextures(1, &id);
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsValid())
|
return std::unique_ptr<OpenGLTexture>(new OpenGLTexture(width, height, layers, levels, samples, type, format, id));
|
||||||
Destroy();
|
|
||||||
|
|
||||||
m_id = id;
|
|
||||||
m_width = static_cast<u16>(width);
|
|
||||||
m_height = static_cast<u16>(height);
|
|
||||||
m_layers = static_cast<u8>(layers);
|
|
||||||
m_levels = static_cast<u8>(levels);
|
|
||||||
m_samples = static_cast<u8>(samples);
|
|
||||||
m_type = type;
|
|
||||||
m_format = format;
|
|
||||||
m_state = GPUTexture::State::Dirty;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLTexture::Destroy()
|
|
||||||
{
|
|
||||||
if (m_id != 0)
|
|
||||||
{
|
|
||||||
OpenGLDevice::GetInstance().UnbindTexture(this);
|
|
||||||
glDeleteTextures(1, &m_id);
|
|
||||||
m_id = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ClearBaseProperties();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLTexture::CommitClear()
|
void OpenGLTexture::CommitClear()
|
||||||
|
|
|
@ -15,7 +15,6 @@ class OpenGLTexture final : public GPUTexture
|
||||||
friend OpenGLDevice;
|
friend OpenGLDevice;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
OpenGLTexture();
|
|
||||||
OpenGLTexture(const OpenGLTexture&) = delete;
|
OpenGLTexture(const OpenGLTexture&) = delete;
|
||||||
~OpenGLTexture();
|
~OpenGLTexture();
|
||||||
|
|
||||||
|
@ -23,16 +22,15 @@ public:
|
||||||
static const std::tuple<GLenum, GLenum, GLenum>& GetPixelFormatMapping(Format format, bool gles);
|
static const std::tuple<GLenum, GLenum, GLenum>& GetPixelFormatMapping(Format format, bool gles);
|
||||||
|
|
||||||
ALWAYS_INLINE GLuint GetGLId() const { return m_id; }
|
ALWAYS_INLINE GLuint GetGLId() const { return m_id; }
|
||||||
bool IsValid() const override { return m_id != 0; }
|
|
||||||
bool Update(u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch, u32 layer = 0, u32 level = 0) override;
|
bool Update(u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch, u32 layer = 0, u32 level = 0) override;
|
||||||
bool Map(void** map, u32* map_stride, u32 x, u32 y, u32 width, u32 height, u32 layer = 0, u32 level = 0) override;
|
bool Map(void** map, u32* map_stride, u32 x, u32 y, u32 width, u32 height, u32 layer = 0, u32 level = 0) override;
|
||||||
void Unmap() override;
|
void Unmap() override;
|
||||||
|
|
||||||
void SetDebugName(const std::string_view& name) override;
|
void SetDebugName(const std::string_view& name) override;
|
||||||
|
|
||||||
bool Create(u32 width, u32 height, u32 layers, u32 levels, u32 samples, Type type, Format format,
|
static std::unique_ptr<OpenGLTexture> Create(u32 width, u32 height, u32 layers, u32 levels, u32 samples, Type type,
|
||||||
const void* data = nullptr, u32 data_pitch = 0);
|
Format format, const void* data = nullptr, u32 data_pitch = 0);
|
||||||
void Destroy();
|
|
||||||
|
|
||||||
bool UseTextureStorage() const;
|
bool UseTextureStorage() const;
|
||||||
|
|
||||||
|
@ -46,6 +44,8 @@ public:
|
||||||
OpenGLTexture& operator=(const OpenGLTexture&) = delete;
|
OpenGLTexture& operator=(const OpenGLTexture&) = delete;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
OpenGLTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, Type type, Format format, GLuint id);
|
||||||
|
|
||||||
GLuint m_id = 0;
|
GLuint m_id = 0;
|
||||||
|
|
||||||
u32 m_map_offset = 0;
|
u32 m_map_offset = 0;
|
||||||
|
|
|
@ -2414,6 +2414,7 @@ bool VulkanDevice::CheckFeatures(FeatureMask disabled_features)
|
||||||
m_features.partial_msaa_resolve = true;
|
m_features.partial_msaa_resolve = true;
|
||||||
m_features.shader_cache = true;
|
m_features.shader_cache = true;
|
||||||
m_features.pipeline_cache = true;
|
m_features.pipeline_cache = true;
|
||||||
|
m_features.prefer_unused_textures = true;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,6 @@ public:
|
||||||
|
|
||||||
VkImageLayout GetVkLayout() const;
|
VkImageLayout GetVkLayout() const;
|
||||||
|
|
||||||
bool IsValid() const override { return (m_image != VK_NULL_HANDLE); }
|
|
||||||
bool Update(u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch, u32 layer = 0, u32 level = 0) override;
|
bool Update(u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch, u32 layer = 0, u32 level = 0) override;
|
||||||
bool Map(void** map, u32* map_stride, u32 x, u32 y, u32 width, u32 height, u32 layer = 0, u32 level = 0) override;
|
bool Map(void** map, u32* map_stride, u32 x, u32 y, u32 width, u32 height, u32 layer = 0, u32 level = 0) override;
|
||||||
void Unmap() override;
|
void Unmap() override;
|
||||||
|
|
Loading…
Reference in New Issue