GPUDevice: Support generating mipmaps
This commit is contained in:
parent
e647192437
commit
3ff1b04576
|
@ -31,7 +31,6 @@
|
|||
X(GPUDevice) \
|
||||
X(GPUDump) \
|
||||
X(GPUShaderCache) \
|
||||
X(GPUTexture) \
|
||||
X(GPUTextureCache) \
|
||||
X(GPU_HW) \
|
||||
X(GPU_SW) \
|
||||
|
|
|
@ -1470,7 +1470,8 @@ void GPU::WriteGP1(u32 value)
|
|||
}
|
||||
break;
|
||||
|
||||
[[unlikely]] default : ERROR_LOG("Unimplemented GP1 command 0x{:02X}", command);
|
||||
[[unlikely]] default:
|
||||
ERROR_LOG("Unimplemented GP1 command 0x{:02X}", command);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1518,7 +1519,8 @@ void GPU::HandleGetGPUInfoCommand(u32 value)
|
|||
}
|
||||
break;
|
||||
|
||||
[[unlikely]] default : WARNING_LOG("Unhandled GetGPUInfo(0x{:02X})", subcommand);
|
||||
[[unlikely]] default:
|
||||
WARNING_LOG("Unhandled GetGPUInfo(0x{:02X})", subcommand);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -2213,7 +2215,7 @@ bool GPU::DeinterlaceExtractField(u32 dst_bufidx, GPUTexture* src, u32 x, u32 y,
|
|||
m_deinterlace_buffers[dst_bufidx]->GetHeight() != height)
|
||||
{
|
||||
if (!g_gpu_device->ResizeTexture(&m_deinterlace_buffers[dst_bufidx], width, height, GPUTexture::Type::RenderTarget,
|
||||
GPUTexture::Format::RGBA8, false)) [[unlikely]]
|
||||
GPUTexture::Format::RGBA8, GPUTexture::Flags::None, false)) [[unlikely]]
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -2258,7 +2260,7 @@ bool GPU::DeinterlaceSetTargetSize(u32 width, u32 height, bool preserve)
|
|||
m_deinterlace_texture->GetHeight() != height)
|
||||
{
|
||||
if (!g_gpu_device->ResizeTexture(&m_deinterlace_texture, width, height, GPUTexture::Type::RenderTarget,
|
||||
GPUTexture::Format::RGBA8, preserve)) [[unlikely]]
|
||||
GPUTexture::Format::RGBA8, GPUTexture::Flags::None, preserve)) [[unlikely]]
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -2279,7 +2281,7 @@ bool GPU::ApplyChromaSmoothing()
|
|||
m_chroma_smoothing_texture->GetHeight() != height)
|
||||
{
|
||||
if (!g_gpu_device->ResizeTexture(&m_chroma_smoothing_texture, width, height, GPUTexture::Type::RenderTarget,
|
||||
GPUTexture::Format::RGBA8, false))
|
||||
GPUTexture::Format::RGBA8, GPUTexture::Flags::None, false))
|
||||
{
|
||||
ClearDisplayTexture();
|
||||
return false;
|
||||
|
@ -2540,8 +2542,8 @@ bool GPU::RenderScreenshotToBuffer(u32 width, u32 height, const GSVector4i displ
|
|||
const GPUTexture::Format hdformat =
|
||||
g_gpu_device->HasMainSwapChain() ? g_gpu_device->GetMainSwapChain()->GetFormat() : GPUTexture::Format::RGBA8;
|
||||
|
||||
auto render_texture =
|
||||
g_gpu_device->FetchAutoRecycleTexture(width, height, 1, 1, 1, GPUTexture::Type::RenderTarget, hdformat);
|
||||
auto render_texture = g_gpu_device->FetchAutoRecycleTexture(width, height, 1, 1, 1, GPUTexture::Type::RenderTarget,
|
||||
hdformat, GPUTexture::Flags::None);
|
||||
if (!render_texture)
|
||||
return false;
|
||||
|
||||
|
|
|
@ -275,15 +275,9 @@ bool GPU_HW::Initialize(Error* error)
|
|||
|
||||
PrintSettingsToLog();
|
||||
|
||||
if (!CompileCommonShaders(error) || !CompilePipelines(error))
|
||||
if (!CompileCommonShaders(error) || !CompilePipelines(error) || !CreateBuffers(error))
|
||||
return false;
|
||||
|
||||
if (!CreateBuffers())
|
||||
{
|
||||
Error::SetStringView(error, "Failed to create framebuffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_use_texture_cache)
|
||||
{
|
||||
if (!GPUTextureCache::Initialize())
|
||||
|
@ -366,7 +360,7 @@ bool GPU_HW::DoState(StateWrapper& sw, GPUTexture** host_texture, bool update_di
|
|||
->FetchTexture(
|
||||
m_vram_texture->GetWidth(), m_vram_texture->GetHeight(), 1, 1, m_vram_texture->GetSamples(),
|
||||
m_vram_texture->IsMultisampled() ? GPUTexture::Type::RenderTarget : GPUTexture::Type::Texture,
|
||||
GPUTexture::Format::RGBA8, nullptr, 0)
|
||||
GPUTexture::Format::RGBA8, GPUTexture::Flags::None)
|
||||
.release();
|
||||
*host_texture = tex;
|
||||
if (!tex)
|
||||
|
@ -538,8 +532,12 @@ void GPU_HW::UpdateSettings(const Settings& old_settings)
|
|||
g_gpu_device->PurgeTexturePool();
|
||||
g_gpu_device->WaitForGPUIdle();
|
||||
|
||||
if (!CreateBuffers())
|
||||
Error error;
|
||||
if (!CreateBuffers(&error))
|
||||
{
|
||||
ERROR_LOG("Failed to recreate buffers: {}", error.GetDescription());
|
||||
Panic("Failed to recreate buffers.");
|
||||
}
|
||||
|
||||
UpdateDownsamplingLevels();
|
||||
RestoreDeviceContext();
|
||||
|
@ -849,7 +847,7 @@ GPUTexture::Format GPU_HW::GetDepthBufferFormat() const
|
|||
VRAM_DS_FORMAT;
|
||||
}
|
||||
|
||||
bool GPU_HW::CreateBuffers()
|
||||
bool GPU_HW::CreateBuffers(Error* error)
|
||||
{
|
||||
DestroyBuffers();
|
||||
|
||||
|
@ -859,28 +857,30 @@ bool GPU_HW::CreateBuffers()
|
|||
const u8 samples = static_cast<u8>(m_multisamples);
|
||||
const bool needs_depth_buffer = m_write_mask_as_depth || m_pgxp_depth_buffer;
|
||||
|
||||
// Needed for Metal resolve.
|
||||
const GPUTexture::Type read_texture_type = (g_gpu_device->GetRenderAPI() == RenderAPI::Metal && m_multisamples > 1) ?
|
||||
GPUTexture::Type::RWTexture :
|
||||
GPUTexture::Type::Texture;
|
||||
const GPUTexture::Type vram_texture_type =
|
||||
m_use_rov_for_shader_blend ? GPUTexture::Type::RWTexture : GPUTexture::Type::RenderTarget;
|
||||
const GPUTexture::Flags read_texture_flags =
|
||||
(m_multisamples > 1) ? GPUTexture::Flags::AllowMSAAResolveTarget : GPUTexture::Flags::None;
|
||||
const GPUTexture::Flags vram_texture_flags =
|
||||
m_use_rov_for_shader_blend ? GPUTexture::Flags::AllowBindAsImage : GPUTexture::Flags::None;
|
||||
const GPUTexture::Type depth_texture_type =
|
||||
m_use_rov_for_shader_blend ? GPUTexture::Type::RWTexture : GPUTexture::Type::DepthStencil;
|
||||
m_use_rov_for_shader_blend ? GPUTexture::Type::Texture : GPUTexture::Type::DepthStencil;
|
||||
|
||||
if (!(m_vram_texture = g_gpu_device->FetchTexture(texture_width, texture_height, 1, 1, samples, vram_texture_type,
|
||||
VRAM_RT_FORMAT)) ||
|
||||
(needs_depth_buffer &&
|
||||
!(m_vram_depth_texture = g_gpu_device->FetchTexture(texture_width, texture_height, 1, 1, samples,
|
||||
depth_texture_type, GetDepthBufferFormat()))) ||
|
||||
(m_pgxp_depth_buffer && !(m_vram_depth_copy_texture =
|
||||
g_gpu_device->FetchTexture(texture_width, texture_height, 1, 1, samples,
|
||||
GPUTexture::Type::RenderTarget, VRAM_DS_COLOR_FORMAT))) ||
|
||||
if (!(m_vram_texture =
|
||||
g_gpu_device->FetchTexture(texture_width, texture_height, 1, 1, samples, GPUTexture::Type::RenderTarget,
|
||||
VRAM_RT_FORMAT, vram_texture_flags, nullptr, 0, error)) ||
|
||||
(needs_depth_buffer && !(m_vram_depth_texture = g_gpu_device->FetchTexture(
|
||||
texture_width, texture_height, 1, 1, samples, depth_texture_type,
|
||||
GetDepthBufferFormat(), vram_texture_flags, nullptr, 0, error))) ||
|
||||
(m_pgxp_depth_buffer && !(m_vram_depth_copy_texture = g_gpu_device->FetchTexture(
|
||||
texture_width, texture_height, 1, 1, samples, GPUTexture::Type::RenderTarget,
|
||||
VRAM_DS_COLOR_FORMAT, GPUTexture::Flags::None, nullptr, 0, error))) ||
|
||||
!(m_vram_read_texture =
|
||||
g_gpu_device->FetchTexture(texture_width, texture_height, 1, 1, 1, read_texture_type, VRAM_RT_FORMAT)) ||
|
||||
!(m_vram_readback_texture = g_gpu_device->FetchTexture(VRAM_WIDTH / 2, VRAM_HEIGHT, 1, 1, 1,
|
||||
GPUTexture::Type::RenderTarget, VRAM_RT_FORMAT)))
|
||||
g_gpu_device->FetchTexture(texture_width, texture_height, 1, 1, 1, GPUTexture::Type::Texture, VRAM_RT_FORMAT,
|
||||
read_texture_flags, nullptr, 0, error)) ||
|
||||
!(m_vram_readback_texture =
|
||||
g_gpu_device->FetchTexture(VRAM_WIDTH / 2, VRAM_HEIGHT, 1, 1, 1, GPUTexture::Type::RenderTarget,
|
||||
VRAM_RT_FORMAT, GPUTexture::Flags::None, nullptr, 0, error)))
|
||||
{
|
||||
Error::AddPrefix(error, "Failed to create VRAM textures: ");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -895,26 +895,28 @@ bool GPU_HW::CreateBuffers()
|
|||
DEV_LOG("Trying to import guest VRAM buffer for downloads...");
|
||||
m_vram_readback_download_texture = g_gpu_device->CreateDownloadTexture(
|
||||
m_vram_readback_texture->GetWidth(), m_vram_readback_texture->GetHeight(), m_vram_readback_texture->GetFormat(),
|
||||
g_vram, sizeof(g_vram), VRAM_WIDTH * sizeof(u16));
|
||||
g_vram, sizeof(g_vram), VRAM_WIDTH * sizeof(u16), error);
|
||||
if (!m_vram_readback_download_texture)
|
||||
ERROR_LOG("Failed to create imported readback buffer");
|
||||
}
|
||||
if (!m_vram_readback_download_texture)
|
||||
{
|
||||
m_vram_readback_download_texture = g_gpu_device->CreateDownloadTexture(
|
||||
m_vram_readback_texture->GetWidth(), m_vram_readback_texture->GetHeight(), m_vram_readback_texture->GetFormat());
|
||||
m_vram_readback_download_texture =
|
||||
g_gpu_device->CreateDownloadTexture(m_vram_readback_texture->GetWidth(), m_vram_readback_texture->GetHeight(),
|
||||
m_vram_readback_texture->GetFormat(), error);
|
||||
if (!m_vram_readback_download_texture)
|
||||
{
|
||||
ERROR_LOG("Failed to create readback download texture");
|
||||
Error::AddPrefix(error, "Failed to create readback download texture: ");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (g_gpu_device->GetFeatures().supports_texture_buffers)
|
||||
{
|
||||
if (!(m_vram_upload_buffer =
|
||||
g_gpu_device->CreateTextureBuffer(GPUTextureBuffer::Format::R16UI, GPUDevice::MIN_TEXEL_BUFFER_ELEMENTS)))
|
||||
if (!(m_vram_upload_buffer = g_gpu_device->CreateTextureBuffer(GPUTextureBuffer::Format::R16UI,
|
||||
GPUDevice::MIN_TEXEL_BUFFER_ELEMENTS, error)))
|
||||
{
|
||||
Error::AddPrefix(error, "Failed to create texture buffer: ");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2930,9 +2932,9 @@ bool GPU_HW::BlitVRAMReplacementTexture(const GPUTextureCache::TextureReplacemen
|
|||
{
|
||||
g_gpu_device->RecycleTexture(std::move(m_vram_replacement_texture));
|
||||
|
||||
if (!(m_vram_replacement_texture =
|
||||
g_gpu_device->FetchTexture(tex->GetWidth(), tex->GetHeight(), 1, 1, 1, GPUTexture::Type::DynamicTexture,
|
||||
GPUTexture::Format::RGBA8, tex->GetPixels(), tex->GetPitch())))
|
||||
if (!(m_vram_replacement_texture = g_gpu_device->FetchTexture(
|
||||
tex->GetWidth(), tex->GetHeight(), 1, 1, 1, GPUTexture::Type::Texture, GPUTexture::Format::RGBA8,
|
||||
GPUTexture::Flags::None, tex->GetPixels(), tex->GetPitch())))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -3402,7 +3404,7 @@ void GPU_HW::UpdateVRAMOnGPU(u32 x, u32 y, u32 width, u32 height, const void* da
|
|||
{
|
||||
map_index = 0;
|
||||
upload_texture = g_gpu_device->FetchTexture(width, height, 1, 1, 1, GPUTexture::Type::Texture,
|
||||
GPUTexture::Format::R16U, data, data_pitch);
|
||||
GPUTexture::Format::R16U, GPUTexture::Flags::None, data, data_pitch);
|
||||
if (!upload_texture)
|
||||
{
|
||||
ERROR_LOG("Failed to get {}x{} upload texture. Things are gonna break.", width, height);
|
||||
|
@ -3938,7 +3940,8 @@ void GPU_HW::UpdateDisplay()
|
|||
m_vram_extract_texture->GetHeight() != read_height)
|
||||
{
|
||||
if (!g_gpu_device->ResizeTexture(&m_vram_extract_texture, scaled_display_width, read_height,
|
||||
GPUTexture::Type::RenderTarget, GPUTexture::Format::RGBA8)) [[unlikely]]
|
||||
GPUTexture::Type::RenderTarget, GPUTexture::Format::RGBA8,
|
||||
GPUTexture::Flags::None)) [[unlikely]]
|
||||
{
|
||||
ClearDisplayTexture();
|
||||
return;
|
||||
|
@ -3952,7 +3955,7 @@ void GPU_HW::UpdateDisplay()
|
|||
((m_vram_extract_depth_texture && m_vram_extract_depth_texture->GetWidth() == scaled_display_width &&
|
||||
m_vram_extract_depth_texture->GetHeight() == scaled_display_height) ||
|
||||
!g_gpu_device->ResizeTexture(&m_vram_extract_depth_texture, scaled_display_width, scaled_display_height,
|
||||
GPUTexture::Type::RenderTarget, VRAM_DS_COLOR_FORMAT)))
|
||||
GPUTexture::Type::RenderTarget, VRAM_DS_COLOR_FORMAT, GPUTexture::Flags::None)))
|
||||
{
|
||||
depth_source->MakeReadyForSampling();
|
||||
g_gpu_device->InvalidateRenderTarget(m_vram_extract_depth_texture.get());
|
||||
|
@ -4090,15 +4093,16 @@ void GPU_HW::DownsampleFramebufferAdaptive(GPUTexture* source, u32 left, u32 top
|
|||
if (!m_downsample_texture || m_downsample_texture->GetWidth() != width || m_downsample_texture->GetHeight() != height)
|
||||
{
|
||||
g_gpu_device->RecycleTexture(std::move(m_downsample_texture));
|
||||
m_downsample_texture =
|
||||
g_gpu_device->FetchTexture(width, height, 1, 1, 1, GPUTexture::Type::RenderTarget, VRAM_RT_FORMAT);
|
||||
m_downsample_texture = g_gpu_device->FetchTexture(width, height, 1, 1, 1, GPUTexture::Type::RenderTarget,
|
||||
VRAM_RT_FORMAT, GPUTexture::Flags::None);
|
||||
}
|
||||
std::unique_ptr<GPUTexture, GPUDevice::PooledTextureDeleter> level_texture = g_gpu_device->FetchAutoRecycleTexture(
|
||||
width, height, 1, m_downsample_scale_or_levels, 1, GPUTexture::Type::Texture, VRAM_RT_FORMAT);
|
||||
std::unique_ptr<GPUTexture, GPUDevice::PooledTextureDeleter> weight_texture =
|
||||
g_gpu_device->FetchAutoRecycleTexture(std::max(width >> (m_downsample_scale_or_levels - 1), 1u),
|
||||
std::max(height >> (m_downsample_scale_or_levels - 1), 1u), 1, 1, 1,
|
||||
GPUTexture::Type::RenderTarget, GPUTexture::Format::R8);
|
||||
std::unique_ptr<GPUTexture, GPUDevice::PooledTextureDeleter> level_texture =
|
||||
g_gpu_device->FetchAutoRecycleTexture(width, height, 1, m_downsample_scale_or_levels, 1, GPUTexture::Type::Texture,
|
||||
VRAM_RT_FORMAT, GPUTexture::Flags::None);
|
||||
std::unique_ptr<GPUTexture, GPUDevice::PooledTextureDeleter> weight_texture = g_gpu_device->FetchAutoRecycleTexture(
|
||||
std::max(width >> (m_downsample_scale_or_levels - 1), 1u),
|
||||
std::max(height >> (m_downsample_scale_or_levels - 1), 1u), 1, 1, 1, GPUTexture::Type::RenderTarget,
|
||||
GPUTexture::Format::R8, GPUTexture::Flags::None);
|
||||
if (!m_downsample_texture || !level_texture || !weight_texture)
|
||||
{
|
||||
ERROR_LOG("Failed to create {}x{} RTs for adaptive downsampling", width, height);
|
||||
|
@ -4205,8 +4209,8 @@ void GPU_HW::DownsampleFramebufferBoxFilter(GPUTexture* source, u32 left, u32 to
|
|||
m_downsample_texture->GetHeight() != ds_height)
|
||||
{
|
||||
g_gpu_device->RecycleTexture(std::move(m_downsample_texture));
|
||||
m_downsample_texture =
|
||||
g_gpu_device->FetchTexture(ds_width, ds_height, 1, 1, 1, GPUTexture::Type::RenderTarget, VRAM_RT_FORMAT);
|
||||
m_downsample_texture = g_gpu_device->FetchTexture(ds_width, ds_height, 1, 1, 1, GPUTexture::Type::RenderTarget,
|
||||
VRAM_RT_FORMAT, GPUTexture::Flags::None);
|
||||
}
|
||||
if (!m_downsample_texture)
|
||||
{
|
||||
|
|
|
@ -155,7 +155,7 @@ private:
|
|||
/// Returns true if a depth buffer should be created.
|
||||
GPUTexture::Format GetDepthBufferFormat() const;
|
||||
|
||||
bool CreateBuffers();
|
||||
bool CreateBuffers(Error* error);
|
||||
void ClearFramebuffer();
|
||||
void DestroyBuffers();
|
||||
|
||||
|
|
|
@ -2048,8 +2048,9 @@ GPUTextureCache::HashCacheEntry* GPUTextureCache::LookupHashCache(SourceKey key,
|
|||
entry.ref_count = 0;
|
||||
entry.last_used_frame = 0;
|
||||
entry.sources = {};
|
||||
entry.texture = g_gpu_device->FetchTexture(TEXTURE_PAGE_WIDTH, TEXTURE_PAGE_HEIGHT, 1, 1, 1,
|
||||
GPUTexture::Type::Texture, GPUTexture::Format::RGBA8);
|
||||
entry.texture =
|
||||
g_gpu_device->FetchTexture(TEXTURE_PAGE_WIDTH, TEXTURE_PAGE_HEIGHT, 1, 1, 1, GPUTexture::Type::Texture,
|
||||
GPUTexture::Format::RGBA8, GPUTexture::Flags::None);
|
||||
if (!entry.texture)
|
||||
{
|
||||
ERROR_LOG("Failed to create texture.");
|
||||
|
@ -3285,8 +3286,9 @@ void GPUTextureCache::ApplyTextureReplacements(SourceKey key, HashType tex_hash,
|
|||
{
|
||||
// NOTE: Not recycled, it's unlikely to be reused.
|
||||
s_state.replacement_texture_render_target.reset();
|
||||
if (!(s_state.replacement_texture_render_target = g_gpu_device->CreateTexture(
|
||||
new_width, new_height, 1, 1, 1, GPUTexture::Type::RenderTarget, REPLACEMENT_TEXTURE_FORMAT)))
|
||||
if (!(s_state.replacement_texture_render_target =
|
||||
g_gpu_device->CreateTexture(new_width, new_height, 1, 1, 1, GPUTexture::Type::RenderTarget,
|
||||
REPLACEMENT_TEXTURE_FORMAT, GPUTexture::Flags::None)))
|
||||
{
|
||||
ERROR_LOG("Failed to create {}x{} render target.", new_width, new_height);
|
||||
return;
|
||||
|
@ -3294,8 +3296,8 @@ void GPUTextureCache::ApplyTextureReplacements(SourceKey key, HashType tex_hash,
|
|||
}
|
||||
|
||||
// Grab the actual texture beforehand, in case we OOM.
|
||||
std::unique_ptr<GPUTexture> replacement_tex =
|
||||
g_gpu_device->FetchTexture(new_width, new_height, 1, 1, 1, GPUTexture::Type::Texture, REPLACEMENT_TEXTURE_FORMAT);
|
||||
std::unique_ptr<GPUTexture> replacement_tex = g_gpu_device->FetchTexture(
|
||||
new_width, new_height, 1, 1, 1, GPUTexture::Type::Texture, REPLACEMENT_TEXTURE_FORMAT, GPUTexture::Flags::None);
|
||||
if (!replacement_tex)
|
||||
{
|
||||
ERROR_LOG("Failed to create {}x{} texture.", new_width, new_height);
|
||||
|
@ -3319,7 +3321,7 @@ void GPUTextureCache::ApplyTextureReplacements(SourceKey key, HashType tex_hash,
|
|||
{
|
||||
const auto temp_texture = g_gpu_device->FetchAutoRecycleTexture(
|
||||
si.image.GetWidth(), si.image.GetHeight(), 1, 1, 1, GPUTexture::Type::Texture, REPLACEMENT_TEXTURE_FORMAT,
|
||||
si.image.GetPixels(), si.image.GetPitch());
|
||||
GPUTexture::Flags::None, si.image.GetPixels(), si.image.GetPitch());
|
||||
if (!temp_texture)
|
||||
continue;
|
||||
|
||||
|
|
|
@ -99,8 +99,8 @@ GPUTexture* GPU_SW::GetDisplayTexture(u32 width, u32 height, GPUTexture::Format
|
|||
{
|
||||
ClearDisplayTexture();
|
||||
g_gpu_device->RecycleTexture(std::move(m_upload_texture));
|
||||
m_upload_texture =
|
||||
g_gpu_device->FetchTexture(width, height, 1, 1, 1, GPUTexture::Type::DynamicTexture, format, nullptr, 0);
|
||||
m_upload_texture = g_gpu_device->FetchTexture(width, height, 1, 1, 1, GPUTexture::Type::Texture, format,
|
||||
GPUTexture::Flags::AllowMap, nullptr, 0);
|
||||
if (!m_upload_texture) [[unlikely]]
|
||||
ERROR_LOG("Failed to create {}x{} {} texture", width, height, static_cast<u32>(format));
|
||||
}
|
||||
|
|
|
@ -1049,9 +1049,9 @@ void SaveStateSelectorUI::InitializeListEntry(ListEntry* li, ExtendedSaveStateIn
|
|||
|
||||
if (ssi->screenshot.IsValid())
|
||||
{
|
||||
li->preview_texture = g_gpu_device->FetchTexture(ssi->screenshot.GetWidth(), ssi->screenshot.GetHeight(), 1, 1, 1,
|
||||
GPUTexture::Type::Texture, GPUTexture::Format::RGBA8,
|
||||
ssi->screenshot.GetPixels(), ssi->screenshot.GetPitch());
|
||||
li->preview_texture = g_gpu_device->FetchTexture(
|
||||
ssi->screenshot.GetWidth(), ssi->screenshot.GetHeight(), 1, 1, 1, GPUTexture::Type::Texture,
|
||||
GPUTexture::Format::RGBA8, GPUTexture::Flags::None, ssi->screenshot.GetPixels(), ssi->screenshot.GetPitch());
|
||||
if (!li->preview_texture) [[unlikely]]
|
||||
ERROR_LOG("Failed to upload save state image to GPU");
|
||||
}
|
||||
|
|
|
@ -139,11 +139,8 @@ bool D3D11Device::CreateDeviceAndMainSwapChain(std::string_view adapter, Feature
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!CreateBuffers())
|
||||
{
|
||||
Error::SetStringView(error, "Failed to create buffers");
|
||||
if (!CreateBuffers(error))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -514,11 +511,11 @@ void D3D11Device::WaitForGPUIdle()
|
|||
TrimTexturePool();
|
||||
}
|
||||
|
||||
bool D3D11Device::CreateBuffers()
|
||||
bool D3D11Device::CreateBuffers(Error* error)
|
||||
{
|
||||
if (!m_vertex_buffer.Create(D3D11_BIND_VERTEX_BUFFER, VERTEX_BUFFER_SIZE, VERTEX_BUFFER_SIZE) ||
|
||||
!m_index_buffer.Create(D3D11_BIND_INDEX_BUFFER, INDEX_BUFFER_SIZE, INDEX_BUFFER_SIZE) ||
|
||||
!m_uniform_buffer.Create(D3D11_BIND_CONSTANT_BUFFER, MIN_UNIFORM_BUFFER_SIZE, MAX_UNIFORM_BUFFER_SIZE))
|
||||
if (!m_vertex_buffer.Create(D3D11_BIND_VERTEX_BUFFER, VERTEX_BUFFER_SIZE, VERTEX_BUFFER_SIZE, error) ||
|
||||
!m_index_buffer.Create(D3D11_BIND_INDEX_BUFFER, INDEX_BUFFER_SIZE, INDEX_BUFFER_SIZE, error) ||
|
||||
!m_uniform_buffer.Create(D3D11_BIND_CONSTANT_BUFFER, MIN_UNIFORM_BUFFER_SIZE, MAX_UNIFORM_BUFFER_SIZE, error))
|
||||
{
|
||||
ERROR_LOG("Failed to create vertex/index/uniform buffers.");
|
||||
return false;
|
||||
|
@ -612,7 +609,7 @@ void D3D11Device::ResolveTextureRegion(GPUTexture* dst, u32 dst_x, u32 dst_y, u3
|
|||
|
||||
bool D3D11Device::IsRenderTargetBound(const D3D11Texture* tex) const
|
||||
{
|
||||
if (tex->IsRenderTarget() || tex->IsRWTexture())
|
||||
if (tex->IsRenderTarget() || tex->HasFlag(GPUTexture::Flags::AllowBindAsImage))
|
||||
{
|
||||
for (u32 i = 0; i < m_num_current_render_targets; i++)
|
||||
{
|
||||
|
@ -1053,7 +1050,7 @@ void D3D11Device::SetTextureSampler(u32 slot, GPUTexture* texture, GPUSampler* s
|
|||
|
||||
// Runtime will null these if we don't...
|
||||
DebugAssert(!texture ||
|
||||
!((texture->IsRenderTarget() || texture->IsRWTexture()) &&
|
||||
!((texture->IsRenderTarget() || texture->HasFlag(GPUTexture::Flags::AllowBindAsImage)) &&
|
||||
IsRenderTargetBound(static_cast<D3D11Texture*>(texture))) ||
|
||||
!(texture->IsDepthStencil() &&
|
||||
(!m_current_depth_target || m_current_depth_target != static_cast<D3D11Texture*>(texture))));
|
||||
|
@ -1100,7 +1097,7 @@ void D3D11Device::UnbindTexture(D3D11Texture* tex)
|
|||
}
|
||||
}
|
||||
|
||||
if (tex->IsRenderTarget() || tex->IsRWTexture())
|
||||
if (tex->IsRenderTarget() || tex->HasFlag(GPUTexture::Flags::AllowBindAsImage))
|
||||
{
|
||||
for (u32 i = 0; i < m_num_current_render_targets; i++)
|
||||
{
|
||||
|
|
|
@ -50,15 +50,18 @@ public:
|
|||
std::optional<bool> exclusive_fullscreen_control,
|
||||
Error* error) override;
|
||||
std::unique_ptr<GPUTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||
GPUTexture::Type type, GPUTexture::Format format,
|
||||
const void* data = nullptr, u32 data_stride = 0) override;
|
||||
std::unique_ptr<GPUSampler> CreateSampler(const GPUSampler::Config& config) override;
|
||||
std::unique_ptr<GPUTextureBuffer> CreateTextureBuffer(GPUTextureBuffer::Format format, u32 size_in_elements) override;
|
||||
GPUTexture::Type type, GPUTexture::Format format, GPUTexture::Flags flags,
|
||||
const void* data = nullptr, u32 data_stride = 0,
|
||||
Error* error = nullptr) override;
|
||||
std::unique_ptr<GPUSampler> CreateSampler(const GPUSampler::Config& config, Error* error = nullptr) override;
|
||||
std::unique_ptr<GPUTextureBuffer> CreateTextureBuffer(GPUTextureBuffer::Format format, u32 size_in_elements,
|
||||
Error* error = nullptr) override;
|
||||
|
||||
std::unique_ptr<GPUDownloadTexture> CreateDownloadTexture(u32 width, u32 height, GPUTexture::Format format) override;
|
||||
std::unique_ptr<GPUDownloadTexture> CreateDownloadTexture(u32 width, u32 height, GPUTexture::Format format,
|
||||
void* memory, size_t memory_size,
|
||||
u32 memory_stride) override;
|
||||
Error* error = nullptr) override;
|
||||
std::unique_ptr<GPUDownloadTexture> CreateDownloadTexture(u32 width, u32 height, GPUTexture::Format format,
|
||||
void* memory, size_t memory_size, u32 memory_stride,
|
||||
Error* error = nullptr) override;
|
||||
|
||||
bool SupportsTextureFormat(GPUTexture::Format format) const override;
|
||||
void CopyTextureRegion(GPUTexture* dst, u32 dst_x, u32 dst_y, u32 dst_layer, u32 dst_level, GPUTexture* src,
|
||||
|
@ -141,7 +144,7 @@ private:
|
|||
|
||||
void SetFeatures(FeatureMask disabled_features);
|
||||
|
||||
bool CreateBuffers();
|
||||
bool CreateBuffers(Error* error);
|
||||
void DestroyBuffers();
|
||||
void BindUniformBuffer(u32 offset, u32 size);
|
||||
void UnbindComputePipeline();
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "common/assert.h"
|
||||
#include "common/error.h"
|
||||
#include "common/log.h"
|
||||
#include "common/small_string.h"
|
||||
|
||||
LOG_CHANNEL(GPUDevice);
|
||||
|
||||
|
@ -27,7 +28,7 @@ D3D11StreamBuffer::~D3D11StreamBuffer()
|
|||
Destroy();
|
||||
}
|
||||
|
||||
bool D3D11StreamBuffer::Create(D3D11_BIND_FLAG bind_flags, u32 min_size, u32 max_size)
|
||||
bool D3D11StreamBuffer::Create(D3D11_BIND_FLAG bind_flags, u32 min_size, u32 max_size, Error* error)
|
||||
{
|
||||
D3D11_FEATURE_DATA_D3D11_OPTIONS options = {};
|
||||
HRESULT hr = D3D11Device::GetD3DDevice()->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS, &options, sizeof(options));
|
||||
|
@ -72,7 +73,7 @@ bool D3D11StreamBuffer::Create(D3D11_BIND_FLAG bind_flags, u32 min_size, u32 max
|
|||
hr = D3D11Device::GetD3DDevice()->CreateBuffer(&desc, nullptr, &buffer);
|
||||
if (FAILED(hr)) [[unlikely]]
|
||||
{
|
||||
ERROR_LOG("Creating buffer failed: {}", Error::CreateHResult(hr).GetDescription());
|
||||
Error::SetHResult(error, TinyString::from_format("CreateBuffer({}) failed: ", create_size), hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#include <d3d11_1.h>
|
||||
#include <wrl/client.h>
|
||||
|
||||
class Error;
|
||||
|
||||
class D3D11StreamBuffer
|
||||
{
|
||||
public:
|
||||
|
@ -26,7 +28,7 @@ public:
|
|||
ALWAYS_INLINE bool IsMapped() const { return m_mapped; }
|
||||
ALWAYS_INLINE bool IsUsingMapNoOverwrite() const { return m_use_map_no_overwrite; }
|
||||
|
||||
bool Create(D3D11_BIND_FLAG bind_flags, u32 min_size, u32 max_size);
|
||||
bool Create(D3D11_BIND_FLAG bind_flags, u32 min_size, u32 max_size, Error* error);
|
||||
void Destroy();
|
||||
|
||||
struct MappingResult
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "d3d_common.h"
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/error.h"
|
||||
#include "common/log.h"
|
||||
#include "common/string_util.h"
|
||||
|
||||
|
@ -17,9 +18,11 @@ LOG_CHANNEL(GPUDevice);
|
|||
|
||||
std::unique_ptr<GPUTexture> D3D11Device::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||
GPUTexture::Type type, GPUTexture::Format format,
|
||||
const void* data, u32 data_stride)
|
||||
GPUTexture::Flags flags, const void* data /* = nullptr */,
|
||||
u32 data_stride /* = 0 */, Error* error /* = nullptr */)
|
||||
{
|
||||
return D3D11Texture::Create(m_device.Get(), width, height, layers, levels, samples, type, format, data, data_stride);
|
||||
return D3D11Texture::Create(m_device.Get(), width, height, layers, levels, samples, type, format, flags, data,
|
||||
data_stride, error);
|
||||
}
|
||||
|
||||
bool D3D11Device::SupportsTextureFormat(GPUTexture::Format format) const
|
||||
|
@ -44,7 +47,7 @@ void D3D11Sampler::SetDebugName(std::string_view name)
|
|||
SetD3DDebugObjectName(m_ss.Get(), name);
|
||||
}
|
||||
|
||||
std::unique_ptr<GPUSampler> D3D11Device::CreateSampler(const GPUSampler::Config& config)
|
||||
std::unique_ptr<GPUSampler> D3D11Device::CreateSampler(const GPUSampler::Config& config, Error* error)
|
||||
{
|
||||
static constexpr std::array<D3D11_TEXTURE_ADDRESS_MODE, static_cast<u8>(GPUSampler::AddressMode::MaxCount)> ta = {{
|
||||
D3D11_TEXTURE_ADDRESS_WRAP, // Repeat
|
||||
|
@ -87,7 +90,7 @@ std::unique_ptr<GPUSampler> D3D11Device::CreateSampler(const GPUSampler::Config&
|
|||
const HRESULT hr = m_device->CreateSamplerState(&desc, ss.GetAddressOf());
|
||||
if (FAILED(hr)) [[unlikely]]
|
||||
{
|
||||
ERROR_LOG("CreateSamplerState() failed: {:08X}", static_cast<unsigned>(hr));
|
||||
Error::SetHResult(error, "CreateSamplerState() failed: ", hr);
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -95,10 +98,10 @@ std::unique_ptr<GPUSampler> D3D11Device::CreateSampler(const GPUSampler::Config&
|
|||
}
|
||||
|
||||
D3D11Texture::D3D11Texture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, Type type, Format format,
|
||||
ComPtr<ID3D11Texture2D> texture, ComPtr<ID3D11ShaderResourceView> srv,
|
||||
Flags flags, ComPtr<ID3D11Texture2D> texture, ComPtr<ID3D11ShaderResourceView> srv,
|
||||
ComPtr<ID3D11View> rtv_dsv, ComPtr<ID3D11UnorderedAccessView> uav)
|
||||
: GPUTexture(static_cast<u16>(width), static_cast<u16>(height), static_cast<u8>(layers), static_cast<u8>(levels),
|
||||
static_cast<u8>(samples), type, format),
|
||||
static_cast<u8>(samples), type, format, flags),
|
||||
m_texture(std::move(texture)), m_srv(std::move(srv)), m_rtv_dsv(std::move(rtv_dsv)), m_uav(std::move(uav))
|
||||
{
|
||||
}
|
||||
|
@ -127,7 +130,7 @@ void D3D11Texture::CommitClear(ID3D11DeviceContext1* context)
|
|||
else
|
||||
context->ClearDepthStencilView(GetD3DDSV(), D3D11_CLEAR_DEPTH, GetClearDepth(), 0);
|
||||
}
|
||||
else if (IsRenderTarget() || IsRWTexture())
|
||||
else if (IsRenderTarget())
|
||||
{
|
||||
if (m_state == GPUTexture::State::Invalidated)
|
||||
context->DiscardView(GetD3DRTV());
|
||||
|
@ -141,7 +144,7 @@ void D3D11Texture::CommitClear(ID3D11DeviceContext1* context)
|
|||
bool D3D11Texture::Update(u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch, u32 layer /*= 0*/,
|
||||
u32 level /*= 0*/)
|
||||
{
|
||||
if (m_type == Type::DynamicTexture)
|
||||
if (HasFlag(Flags::AllowMap))
|
||||
{
|
||||
void* map;
|
||||
u32 map_stride;
|
||||
|
@ -171,7 +174,7 @@ bool D3D11Texture::Update(u32 x, u32 y, u32 width, u32 height, const void* data,
|
|||
bool D3D11Texture::Map(void** map, u32* map_stride, u32 x, u32 y, u32 width, u32 height, u32 layer /*= 0*/,
|
||||
u32 level /*= 0*/)
|
||||
{
|
||||
if (m_type != Type::DynamicTexture || (x + width) > GetMipWidth(level) || (y + height) > GetMipHeight(level) ||
|
||||
if (!HasFlag(Flags::AllowMap) || (x + width) > GetMipWidth(level) || (y + height) > GetMipHeight(level) ||
|
||||
layer > m_layers || level > m_levels)
|
||||
{
|
||||
return false;
|
||||
|
@ -207,6 +210,12 @@ void D3D11Texture::Unmap()
|
|||
m_mapped_subresource = 0;
|
||||
}
|
||||
|
||||
void D3D11Texture::GenerateMipmaps()
|
||||
{
|
||||
DebugAssert(HasFlag(Flags::AllowGenerateMipmaps));
|
||||
D3D11Device::GetD3DContext()->GenerateMips(m_srv.Get());
|
||||
}
|
||||
|
||||
void D3D11Texture::SetDebugName(std::string_view name)
|
||||
{
|
||||
SetD3DDebugObjectName(m_texture.Get(), name);
|
||||
|
@ -218,43 +227,57 @@ DXGI_FORMAT D3D11Texture::GetDXGIFormat() const
|
|||
}
|
||||
|
||||
std::unique_ptr<D3D11Texture> D3D11Texture::Create(ID3D11Device* 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 */)
|
||||
u32 samples, Type type, Format format, Flags flags,
|
||||
const void* initial_data, u32 initial_data_stride, Error* error)
|
||||
{
|
||||
if (!ValidateConfig(width, height, layers, layers, samples, type, format))
|
||||
if (!ValidateConfig(width, height, layers, levels, samples, type, format, flags, error))
|
||||
return nullptr;
|
||||
|
||||
u32 bind_flags = 0;
|
||||
D3D11_USAGE usage = D3D11_USAGE_DEFAULT;
|
||||
u32 cpu_access = 0;
|
||||
u32 misc = 0;
|
||||
switch (type)
|
||||
{
|
||||
case Type::RenderTarget:
|
||||
bind_flags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
|
||||
break;
|
||||
case Type::DepthStencil:
|
||||
bind_flags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE;
|
||||
break;
|
||||
case Type::Texture:
|
||||
bind_flags = D3D11_BIND_SHADER_RESOURCE;
|
||||
break;
|
||||
case Type::DynamicTexture:
|
||||
bind_flags = D3D11_BIND_SHADER_RESOURCE;
|
||||
|
||||
case Type::RenderTarget:
|
||||
bind_flags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
|
||||
break;
|
||||
|
||||
case Type::DepthStencil:
|
||||
bind_flags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE;
|
||||
break;
|
||||
|
||||
DefaultCaseIsUnreachable();
|
||||
}
|
||||
|
||||
if ((flags & Flags::AllowBindAsImage) != Flags::None)
|
||||
{
|
||||
DebugAssert(levels == 1);
|
||||
bind_flags |= D3D11_BIND_UNORDERED_ACCESS;
|
||||
}
|
||||
|
||||
if ((flags & Flags::AllowGenerateMipmaps) != Flags::None)
|
||||
{
|
||||
// Needs RT annoyingly.
|
||||
bind_flags |= D3D11_BIND_RENDER_TARGET;
|
||||
misc = D3D11_RESOURCE_MISC_GENERATE_MIPS;
|
||||
}
|
||||
|
||||
if ((flags & Flags::AllowMap) != Flags::None)
|
||||
{
|
||||
DebugAssert(type == Type::Texture);
|
||||
usage = D3D11_USAGE_DYNAMIC;
|
||||
cpu_access = D3D11_CPU_ACCESS_WRITE;
|
||||
break;
|
||||
case Type::RWTexture:
|
||||
bind_flags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
const D3DCommon::DXGIFormatMapping& fm = D3DCommon::GetFormatMapping(format);
|
||||
|
||||
CD3D11_TEXTURE2D_DESC desc(fm.resource_format, width, height, layers, levels, bind_flags, usage, cpu_access, samples,
|
||||
0, 0);
|
||||
0, misc);
|
||||
|
||||
D3D11_SUBRESOURCE_DATA srd;
|
||||
srd.pSysMem = initial_data;
|
||||
|
@ -265,9 +288,7 @@ std::unique_ptr<D3D11Texture> D3D11Texture::Create(ID3D11Device* device, u32 wid
|
|||
const HRESULT tex_hr = device->CreateTexture2D(&desc, initial_data ? &srd : nullptr, texture.GetAddressOf());
|
||||
if (FAILED(tex_hr))
|
||||
{
|
||||
ERROR_LOG("Create texture failed: 0x{:08X} ({}x{} levels:{} samples:{} format:{} bind_flags:{:X} initial_data:{})",
|
||||
static_cast<unsigned>(tex_hr), width, height, levels, samples, static_cast<unsigned>(format), bind_flags,
|
||||
initial_data);
|
||||
Error::SetHResult(error, "CreateTexture2D() failed: ", tex_hr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -288,7 +309,7 @@ std::unique_ptr<D3D11Texture> D3D11Texture::Create(ID3D11Device* device, u32 wid
|
|||
const HRESULT hr = device->CreateShaderResourceView(texture.Get(), &srv_desc, srv.GetAddressOf());
|
||||
if (FAILED(hr)) [[unlikely]]
|
||||
{
|
||||
ERROR_LOG("Create SRV for texture failed: 0x{:08X}", static_cast<unsigned>(hr));
|
||||
Error::SetHResult(error, "CreateShaderResourceView() failed: ", hr);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
@ -303,7 +324,7 @@ std::unique_ptr<D3D11Texture> D3D11Texture::Create(ID3D11Device* device, u32 wid
|
|||
const HRESULT hr = device->CreateRenderTargetView(texture.Get(), &rtv_desc, rtv.GetAddressOf());
|
||||
if (FAILED(hr)) [[unlikely]]
|
||||
{
|
||||
ERROR_LOG("Create RTV for texture failed: 0x{:08X}", static_cast<unsigned>(hr));
|
||||
Error::SetHResult(error, "CreateRenderTargetView() failed: ", hr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -318,7 +339,7 @@ std::unique_ptr<D3D11Texture> D3D11Texture::Create(ID3D11Device* device, u32 wid
|
|||
const HRESULT hr = device->CreateDepthStencilView(texture.Get(), &dsv_desc, dsv.GetAddressOf());
|
||||
if (FAILED(hr)) [[unlikely]]
|
||||
{
|
||||
ERROR_LOG("Create DSV for texture failed: 0x{:08X}", static_cast<unsigned>(hr));
|
||||
Error::SetHResult(error, "CreateDepthStencilView() failed: ", hr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -334,12 +355,12 @@ std::unique_ptr<D3D11Texture> D3D11Texture::Create(ID3D11Device* device, u32 wid
|
|||
const HRESULT hr = device->CreateUnorderedAccessView(texture.Get(), &uav_desc, uav.GetAddressOf());
|
||||
if (FAILED(hr)) [[unlikely]]
|
||||
{
|
||||
ERROR_LOG("Create UAV for texture failed: 0x{:08X}", static_cast<unsigned>(hr));
|
||||
Error::SetHResult(error, "CreateUnorderedAccessView() failed: ", hr);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return std::unique_ptr<D3D11Texture>(new D3D11Texture(width, height, layers, levels, samples, type, format,
|
||||
return std::unique_ptr<D3D11Texture>(new D3D11Texture(width, height, layers, levels, samples, type, format, flags,
|
||||
std::move(texture), std::move(srv), std::move(rtv_dsv),
|
||||
std::move(uav)));
|
||||
}
|
||||
|
@ -350,10 +371,10 @@ D3D11TextureBuffer::D3D11TextureBuffer(Format format, u32 size_in_elements) : GP
|
|||
|
||||
D3D11TextureBuffer::~D3D11TextureBuffer() = default;
|
||||
|
||||
bool D3D11TextureBuffer::CreateBuffer()
|
||||
bool D3D11TextureBuffer::CreateBuffer(Error* error)
|
||||
{
|
||||
const u32 size_in_bytes = GetSizeInBytes();
|
||||
if (!m_buffer.Create(D3D11_BIND_SHADER_RESOURCE, size_in_bytes, size_in_bytes))
|
||||
if (!m_buffer.Create(D3D11_BIND_SHADER_RESOURCE, size_in_bytes, size_in_bytes, error))
|
||||
return false;
|
||||
|
||||
static constexpr std::array<DXGI_FORMAT, static_cast<u32>(Format::MaxCount)> dxgi_formats = {{
|
||||
|
@ -366,7 +387,7 @@ bool D3D11TextureBuffer::CreateBuffer()
|
|||
D3D11Device::GetD3DDevice()->CreateShaderResourceView(m_buffer.GetD3DBuffer(), &srv_desc, m_srv.GetAddressOf());
|
||||
if (FAILED(hr)) [[unlikely]]
|
||||
{
|
||||
ERROR_LOG("CreateShaderResourceView() failed: {:08X}", static_cast<unsigned>(hr));
|
||||
Error::SetHResult(error, "CreateShaderResourceView() failed: ", hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -395,10 +416,10 @@ void D3D11TextureBuffer::SetDebugName(std::string_view name)
|
|||
}
|
||||
|
||||
std::unique_ptr<GPUTextureBuffer> D3D11Device::CreateTextureBuffer(GPUTextureBuffer::Format format,
|
||||
u32 size_in_elements)
|
||||
u32 size_in_elements, Error* error /* = nullptr */)
|
||||
{
|
||||
std::unique_ptr<D3D11TextureBuffer> tb = std::make_unique<D3D11TextureBuffer>(format, size_in_elements);
|
||||
if (!tb->CreateBuffer())
|
||||
if (!tb->CreateBuffer(error))
|
||||
tb.reset();
|
||||
|
||||
return tb;
|
||||
|
@ -416,7 +437,8 @@ D3D11DownloadTexture::~D3D11DownloadTexture()
|
|||
D3D11DownloadTexture::Unmap();
|
||||
}
|
||||
|
||||
std::unique_ptr<D3D11DownloadTexture> D3D11DownloadTexture::Create(u32 width, u32 height, GPUTexture::Format format)
|
||||
std::unique_ptr<D3D11DownloadTexture> D3D11DownloadTexture::Create(u32 width, u32 height, GPUTexture::Format format,
|
||||
Error* error)
|
||||
{
|
||||
D3D11_TEXTURE2D_DESC desc = {};
|
||||
desc.Width = width;
|
||||
|
@ -433,7 +455,7 @@ std::unique_ptr<D3D11DownloadTexture> D3D11DownloadTexture::Create(u32 width, u3
|
|||
HRESULT hr = D3D11Device::GetD3DDevice()->CreateTexture2D(&desc, nullptr, tex.GetAddressOf());
|
||||
if (FAILED(hr))
|
||||
{
|
||||
ERROR_LOG("CreateTexture2D() failed: {:08X}", hr);
|
||||
Error::SetHResult(error, "CreateTexture2D() failed: ", hr);
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -520,15 +542,16 @@ void D3D11DownloadTexture::SetDebugName(std::string_view name)
|
|||
SetD3DDebugObjectName(m_texture.Get(), name);
|
||||
}
|
||||
|
||||
std::unique_ptr<GPUDownloadTexture> D3D11Device::CreateDownloadTexture(u32 width, u32 height, GPUTexture::Format format)
|
||||
std::unique_ptr<GPUDownloadTexture> D3D11Device::CreateDownloadTexture(u32 width, u32 height, GPUTexture::Format format,
|
||||
Error* error /* = nullptr */)
|
||||
{
|
||||
return D3D11DownloadTexture::Create(width, height, format);
|
||||
return D3D11DownloadTexture::Create(width, height, format, error);
|
||||
}
|
||||
|
||||
std::unique_ptr<GPUDownloadTexture> D3D11Device::CreateDownloadTexture(u32 width, u32 height, GPUTexture::Format format,
|
||||
void* memory, size_t memory_size,
|
||||
u32 memory_stride)
|
||||
u32 memory_stride, Error* error /* = nullptr */)
|
||||
{
|
||||
ERROR_LOG("D3D11 cannot import memory for download textures");
|
||||
Error::SetStringView(error, "D3D11 cannot import memory for download textures");
|
||||
return {};
|
||||
}
|
||||
|
|
|
@ -77,8 +77,8 @@ public:
|
|||
ALWAYS_INLINE operator bool() const { return static_cast<bool>(m_texture); }
|
||||
|
||||
static std::unique_ptr<D3D11Texture> Create(ID3D11Device* 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);
|
||||
u32 samples, Type type, Format format, Flags flags,
|
||||
const void* initial_data, u32 initial_data_stride, Error* error);
|
||||
|
||||
D3D11_TEXTURE2D_DESC GetDesc() const;
|
||||
void CommitClear(ID3D11DeviceContext1* context);
|
||||
|
@ -86,11 +86,12 @@ public:
|
|||
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;
|
||||
void Unmap() override;
|
||||
void GenerateMipmaps() override;
|
||||
|
||||
void SetDebugName(std::string_view name) override;
|
||||
|
||||
private:
|
||||
D3D11Texture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, Type type, Format format,
|
||||
D3D11Texture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, Type type, Format format, Flags flags,
|
||||
ComPtr<ID3D11Texture2D> texture, ComPtr<ID3D11ShaderResourceView> srv, ComPtr<ID3D11View> rtv_dsv,
|
||||
ComPtr<ID3D11UnorderedAccessView> uav);
|
||||
|
||||
|
@ -111,7 +112,7 @@ public:
|
|||
ALWAYS_INLINE ID3D11ShaderResourceView* GetSRV() const { return m_srv.Get(); }
|
||||
ALWAYS_INLINE ID3D11ShaderResourceView* const* GetSRVArray() const { return m_srv.GetAddressOf(); }
|
||||
|
||||
bool CreateBuffer();
|
||||
bool CreateBuffer(Error* error);
|
||||
|
||||
// Inherited via GPUTextureBuffer
|
||||
void* Map(u32 required_elements) override;
|
||||
|
@ -129,7 +130,7 @@ class D3D11DownloadTexture final : public GPUDownloadTexture
|
|||
public:
|
||||
~D3D11DownloadTexture() override;
|
||||
|
||||
static std::unique_ptr<D3D11DownloadTexture> Create(u32 width, u32 height, GPUTexture::Format format);
|
||||
static std::unique_ptr<D3D11DownloadTexture> Create(u32 width, u32 height, GPUTexture::Format format, Error* error);
|
||||
|
||||
void CopyFromTexture(u32 dst_x, u32 dst_y, GPUTexture* src, u32 src_x, u32 src_y, u32 width, u32 height,
|
||||
u32 src_layer, u32 src_level, bool use_transfer_pitch) override;
|
||||
|
|
|
@ -118,11 +118,6 @@ void D3D12::GraphicsPipelineBuilder::SetMultisamples(u32 multisamples)
|
|||
m_desc.SampleDesc.Count = multisamples;
|
||||
}
|
||||
|
||||
void D3D12::GraphicsPipelineBuilder::SetNoCullRasterizationState()
|
||||
{
|
||||
SetRasterizationState(D3D12_FILL_MODE_SOLID, D3D12_CULL_MODE_NONE, false);
|
||||
}
|
||||
|
||||
void D3D12::GraphicsPipelineBuilder::SetDepthState(bool depth_test, bool depth_write, D3D12_COMPARISON_FUNC compare_op)
|
||||
{
|
||||
m_desc.DepthStencilState.DepthEnable = depth_test;
|
||||
|
@ -141,11 +136,6 @@ void D3D12::GraphicsPipelineBuilder::SetStencilState(bool stencil_test, u8 read_
|
|||
m_desc.DepthStencilState.BackFace = back;
|
||||
}
|
||||
|
||||
void D3D12::GraphicsPipelineBuilder::SetNoDepthTestState()
|
||||
{
|
||||
SetDepthState(false, false, D3D12_COMPARISON_FUNC_ALWAYS);
|
||||
}
|
||||
|
||||
void D3D12::GraphicsPipelineBuilder::SetNoStencilState()
|
||||
{
|
||||
D3D12_DEPTH_STENCILOP_DESC empty = {};
|
||||
|
@ -170,18 +160,6 @@ void D3D12::GraphicsPipelineBuilder::SetBlendState(u32 rt, bool blend_enable, D3
|
|||
m_desc.BlendState.IndependentBlendEnable = TRUE;
|
||||
}
|
||||
|
||||
void D3D12::GraphicsPipelineBuilder::SetColorWriteMask(u32 rt, u8 write_mask /* = D3D12_COLOR_WRITE_ENABLE_ALL */)
|
||||
{
|
||||
m_desc.BlendState.RenderTarget[rt].RenderTargetWriteMask = write_mask;
|
||||
}
|
||||
|
||||
void D3D12::GraphicsPipelineBuilder::SetNoBlendingState()
|
||||
{
|
||||
SetBlendState(0, false, D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD, D3D12_BLEND_ONE, D3D12_BLEND_ZERO,
|
||||
D3D12_BLEND_OP_ADD, D3D12_COLOR_WRITE_ENABLE_ALL);
|
||||
m_desc.BlendState.IndependentBlendEnable = FALSE;
|
||||
}
|
||||
|
||||
void D3D12::GraphicsPipelineBuilder::ClearRenderTargets()
|
||||
{
|
||||
m_desc.NumRenderTargets = 0;
|
||||
|
|
|
@ -80,21 +80,14 @@ public:
|
|||
|
||||
void SetMultisamples(u32 multisamples);
|
||||
|
||||
void SetNoCullRasterizationState();
|
||||
|
||||
void SetDepthState(bool depth_test, bool depth_write, D3D12_COMPARISON_FUNC compare_op);
|
||||
void SetStencilState(bool stencil_test, u8 read_mask, u8 write_mask, const D3D12_DEPTH_STENCILOP_DESC& front,
|
||||
const D3D12_DEPTH_STENCILOP_DESC& back);
|
||||
|
||||
void SetNoDepthTestState();
|
||||
void SetNoStencilState();
|
||||
|
||||
void SetBlendState(u32 rt, bool blend_enable, D3D12_BLEND src_factor, D3D12_BLEND dst_factor, D3D12_BLEND_OP op,
|
||||
D3D12_BLEND alpha_src_factor, D3D12_BLEND alpha_dst_factor, D3D12_BLEND_OP alpha_op,
|
||||
u8 write_mask = D3D12_COLOR_WRITE_ENABLE_ALL);
|
||||
void SetColorWriteMask(u32 rt, u8 write_mask = D3D12_COLOR_WRITE_ENABLE_ALL);
|
||||
|
||||
void SetNoBlendingState();
|
||||
|
||||
void ClearRenderTargets();
|
||||
|
||||
|
|
|
@ -83,7 +83,6 @@ bool D3D12DescriptorHeapManager::Allocate(D3D12DescriptorHandle* handle)
|
|||
return true;
|
||||
}
|
||||
|
||||
Panic("Out of fixed descriptors");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,6 @@ enum : u32
|
|||
FRAGMENT_UNIFORM_BUFFER_SIZE = 8 * 1024 * 1024,
|
||||
TEXTURE_BUFFER_SIZE = 64 * 1024 * 1024,
|
||||
|
||||
// UNIFORM_PUSH_CONSTANTS_STAGES = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
UNIFORM_PUSH_CONSTANTS_SIZE = 128,
|
||||
|
||||
MAX_UNIFORM_BUFFER_SIZE = 1024,
|
||||
|
@ -65,6 +64,55 @@ static DynamicHeapArray<u8> s_pipeline_cache_data;
|
|||
static u32 s_debug_scope_depth = 0;
|
||||
#endif
|
||||
|
||||
static constexpr const u32 s_mipmap_blit_vs[] = {
|
||||
0x43425844, 0xe0f571cf, 0x51234ef3, 0x3a6beab4, 0x141cd2ef, 0x00000001, 0x000003ac, 0x00000005, 0x00000034,
|
||||
0x00000144, 0x00000178, 0x000001d0, 0x00000310, 0x46454452, 0x00000108, 0x00000001, 0x00000068, 0x00000001,
|
||||
0x0000003c, 0xfffe0500, 0x00008100, 0x000000e0, 0x31314452, 0x0000003c, 0x00000018, 0x00000020, 0x00000028,
|
||||
0x00000024, 0x0000000c, 0x00000000, 0x0000005c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000001, 0x00000001, 0x424f4255, 0x6b636f6c, 0xababab00, 0x0000005c, 0x00000001, 0x00000080, 0x00000010,
|
||||
0x00000000, 0x00000000, 0x000000a8, 0x00000000, 0x00000010, 0x00000002, 0x000000bc, 0x00000000, 0xffffffff,
|
||||
0x00000000, 0xffffffff, 0x00000000, 0x72735f75, 0x65725f63, 0x66007463, 0x74616f6c, 0xabab0034, 0x00030001,
|
||||
0x00040001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000b3, 0x7263694d,
|
||||
0x666f736f, 0x52282074, 0x4c482029, 0x53204c53, 0x65646168, 0x6f432072, 0x6c69706d, 0x31207265, 0x00312e30,
|
||||
0x4e475349, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000006, 0x00000001, 0x00000000,
|
||||
0x00000101, 0x565f5653, 0x65747265, 0x00444978, 0x4e47534f, 0x00000050, 0x00000002, 0x00000008, 0x00000038,
|
||||
0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x00000c03, 0x00000041, 0x00000000, 0x00000001, 0x00000003,
|
||||
0x00000001, 0x0000000f, 0x43584554, 0x44524f4f, 0x5f565300, 0x69736f50, 0x6e6f6974, 0xababab00, 0x58454853,
|
||||
0x00000138, 0x00010050, 0x0000004e, 0x0100086a, 0x04000059, 0x00208e46, 0x00000000, 0x00000001, 0x04000060,
|
||||
0x00101012, 0x00000000, 0x00000006, 0x03000065, 0x00102032, 0x00000000, 0x04000067, 0x001020f2, 0x00000001,
|
||||
0x00000001, 0x02000068, 0x00000001, 0x0b00008c, 0x00100012, 0x00000000, 0x00004001, 0x00000001, 0x00004001,
|
||||
0x00000001, 0x0010100a, 0x00000000, 0x00004001, 0x00000000, 0x07000001, 0x00100042, 0x00000000, 0x0010100a,
|
||||
0x00000000, 0x00004001, 0x00000002, 0x05000056, 0x00100032, 0x00000000, 0x00100086, 0x00000000, 0x0b000032,
|
||||
0x00102032, 0x00000000, 0x00100046, 0x00000000, 0x00208ae6, 0x00000000, 0x00000000, 0x00208046, 0x00000000,
|
||||
0x00000000, 0x0f000032, 0x00102032, 0x00000001, 0x00100046, 0x00000000, 0x00004002, 0x40000000, 0xc0000000,
|
||||
0x00000000, 0x00000000, 0x00004002, 0xbf800000, 0x3f800000, 0x00000000, 0x00000000, 0x08000036, 0x001020c2,
|
||||
0x00000001, 0x00004002, 0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x0100003e, 0x54415453, 0x00000094,
|
||||
0x00000007, 0x00000001, 0x00000000, 0x00000003, 0x00000002, 0x00000000, 0x00000001, 0x00000001, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000001, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000};
|
||||
|
||||
static constexpr const u32 s_mipmap_blit_ps[] = {
|
||||
0x43425844, 0x25500f77, 0x71f24271, 0x5f83f8b8, 0x3f405943, 0x00000001, 0x0000026c, 0x00000005, 0x00000034,
|
||||
0x000000f0, 0x00000124, 0x00000158, 0x000001d0, 0x46454452, 0x000000b4, 0x00000000, 0x00000000, 0x00000002,
|
||||
0x0000003c, 0xffff0500, 0x00008100, 0x0000008b, 0x31314452, 0x0000003c, 0x00000018, 0x00000020, 0x00000028,
|
||||
0x00000024, 0x0000000c, 0x00000000, 0x0000007c, 0x00000003, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000001, 0x00000001, 0x00000085, 0x00000002, 0x00000005, 0x00000004, 0xffffffff, 0x00000000, 0x00000001,
|
||||
0x0000000d, 0x706d6173, 0x73735f30, 0x6d617300, 0x4d003070, 0x6f726369, 0x74666f73, 0x29522820, 0x534c4820,
|
||||
0x6853204c, 0x72656461, 0x6d6f4320, 0x656c6970, 0x30312072, 0xab00312e, 0x4e475349, 0x0000002c, 0x00000001,
|
||||
0x00000008, 0x00000020, 0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x00000303, 0x43584554, 0x44524f4f,
|
||||
0xababab00, 0x4e47534f, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000000, 0x00000003,
|
||||
0x00000000, 0x0000000f, 0x545f5653, 0x65677261, 0xabab0074, 0x58454853, 0x00000070, 0x00000050, 0x0000001c,
|
||||
0x0100086a, 0x0300005a, 0x00106000, 0x00000000, 0x04001858, 0x00107000, 0x00000000, 0x00005555, 0x03001062,
|
||||
0x00101032, 0x00000000, 0x03000065, 0x001020f2, 0x00000000, 0x8b000045, 0x800000c2, 0x00155543, 0x001020f2,
|
||||
0x00000000, 0x00101046, 0x00000000, 0x00107e46, 0x00000000, 0x00106000, 0x00000000, 0x0100003e, 0x54415453,
|
||||
0x00000094, 0x00000002, 0x00000000, 0x00000000, 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000001,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000};
|
||||
|
||||
D3D12Device::D3D12Device()
|
||||
{
|
||||
m_render_api = RenderAPI::D3D12;
|
||||
|
@ -523,7 +571,9 @@ bool D3D12Device::CreateDescriptorHeaps(Error* error)
|
|||
m_device->CreateUnorderedAccessView(nullptr, nullptr, &null_uav_desc, m_null_uav_descriptor.cpu_handle);
|
||||
|
||||
// Same for samplers.
|
||||
m_point_sampler = GetSampler(GPUSampler::GetNearestConfig());
|
||||
m_point_sampler = GetSampler(GPUSampler::GetNearestConfig(), error);
|
||||
if (!m_point_sampler) [[unlikely]]
|
||||
return false;
|
||||
for (u32 i = 0; i < MAX_TEXTURE_SAMPLERS; i++)
|
||||
m_current_samplers[i] = m_point_sampler;
|
||||
return true;
|
||||
|
@ -2100,7 +2150,7 @@ void D3D12Device::UnbindTexture(D3D12Texture* tex)
|
|||
}
|
||||
}
|
||||
|
||||
if (tex->IsRenderTarget() || tex->IsRWTexture())
|
||||
if (tex->IsRenderTarget() || tex->HasFlag(GPUTexture::Flags::AllowBindAsImage))
|
||||
{
|
||||
for (u32 i = 0; i < m_num_current_render_targets; i++)
|
||||
{
|
||||
|
@ -2134,6 +2184,137 @@ void D3D12Device::UnbindTextureBuffer(D3D12TextureBuffer* buf)
|
|||
m_dirty_flags |= DIRTY_FLAG_TEXTURES;
|
||||
}
|
||||
|
||||
void D3D12Device::RenderTextureMipmap(D3D12Texture* texture, u32 dst_level, u32 dst_width, u32 dst_height,
|
||||
u32 src_level, u32 src_width, u32 src_height)
|
||||
{
|
||||
ID3D12RootSignature* rootsig =
|
||||
m_root_signatures[0][static_cast<size_t>(GPUPipeline::Layout::SingleTextureAndPushConstants)].Get();
|
||||
ComPtr<ID3D12PipelineState>& pipeline = m_mipmap_render_pipelines[static_cast<size_t>(texture->GetFormat())];
|
||||
if (!pipeline)
|
||||
{
|
||||
D3D12::GraphicsPipelineBuilder gpb;
|
||||
gpb.SetRootSignature(rootsig);
|
||||
gpb.SetPrimitiveTopologyType(D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE);
|
||||
gpb.SetRenderTarget(0, texture->GetDXGIFormat());
|
||||
gpb.SetVertexShader(s_mipmap_blit_vs, std::size(s_mipmap_blit_vs));
|
||||
gpb.SetPixelShader(s_mipmap_blit_ps, std::size(s_mipmap_blit_ps));
|
||||
gpb.SetRasterizationState(D3D12_FILL_MODE_SOLID, D3D12_CULL_MODE_NONE, false);
|
||||
gpb.SetDepthState(false, false, D3D12_COMPARISON_FUNC_ALWAYS);
|
||||
gpb.SetBlendState(0, false, D3D12_BLEND_ZERO, D3D12_BLEND_ONE, D3D12_BLEND_OP_ADD, D3D12_BLEND_ZERO,
|
||||
D3D12_BLEND_ONE, D3D12_BLEND_OP_ADD, D3D12_COLOR_WRITE_ENABLE_ALL);
|
||||
|
||||
const std::wstring name = StringUtil::UTF8StringToWideString(
|
||||
TinyString::from_format("MipmapRender-{}", GPUTexture::GetFormatName(texture->GetFormat())));
|
||||
Error error;
|
||||
if (m_pipeline_library)
|
||||
{
|
||||
HRESULT hr =
|
||||
m_pipeline_library->LoadGraphicsPipeline(name.c_str(), gpb.GetDesc(), IID_PPV_ARGS(pipeline.GetAddressOf()));
|
||||
if (FAILED(hr))
|
||||
{
|
||||
// E_INVALIDARG = not found.
|
||||
if (hr != E_INVALIDARG)
|
||||
ERROR_LOG("LoadGraphicsPipeline() failed with HRESULT {:08X}", static_cast<unsigned>(hr));
|
||||
|
||||
// Need to create it normally.
|
||||
pipeline = gpb.Create(m_device.Get(), &error, false);
|
||||
|
||||
// Store if it wasn't an OOM or something else.
|
||||
if (pipeline && hr == E_INVALIDARG)
|
||||
{
|
||||
hr = m_pipeline_library->StorePipeline(name.c_str(), pipeline.Get());
|
||||
if (FAILED(hr))
|
||||
ERROR_LOG("StorePipeline() failed with HRESULT {:08X}", static_cast<unsigned>(hr));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pipeline = gpb.Create(m_device.Get(), &error, false);
|
||||
}
|
||||
if (!pipeline)
|
||||
{
|
||||
ERROR_LOG("Failed to compile mipmap render pipeline for {}: {}", GPUTexture::GetFormatName(texture->GetFormat()),
|
||||
error.GetDescription());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
EndRenderPass();
|
||||
|
||||
// we need a temporary SRV and RTV for each mip level
|
||||
// Safe to use the init buffer after exec, because everything will be done with the texture.
|
||||
D3D12DescriptorHandle rtv_handle;
|
||||
while (!GetRTVHeapManager().Allocate(&rtv_handle))
|
||||
SubmitCommandList(false, "Allocate RTV for RenderTextureMipmap()");
|
||||
|
||||
D3D12DescriptorHandle srv_handle;
|
||||
while (!GetDescriptorHeapManager().Allocate(&srv_handle))
|
||||
SubmitCommandList(false, "Allocate SRV for RenderTextureMipmap()");
|
||||
|
||||
// Setup views. This will be a partial view for the SRV.
|
||||
D3D12_RENDER_TARGET_VIEW_DESC rtv_desc = {texture->GetDXGIFormat(), D3D12_RTV_DIMENSION_TEXTURE2D};
|
||||
rtv_desc.Texture2D = {dst_level, 0u};
|
||||
m_device->CreateRenderTargetView(texture->GetResource(), &rtv_desc, rtv_handle);
|
||||
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc = {texture->GetDXGIFormat(), D3D12_SRV_DIMENSION_TEXTURE2D,
|
||||
D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING};
|
||||
srv_desc.Texture2D = {src_level, 1u, 0u, 0.0f};
|
||||
m_device->CreateShaderResourceView(texture->GetResource(), &srv_desc, srv_handle);
|
||||
|
||||
// *now* we don't have to worry about running out of anything.
|
||||
ID3D12GraphicsCommandList4* cmdlist = GetCommandList();
|
||||
if (texture->GetResourceState() != D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE)
|
||||
{
|
||||
texture->TransitionSubresourceToState(cmdlist, src_level, texture->GetResourceState(),
|
||||
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
}
|
||||
if (texture->GetResourceState() != D3D12_RESOURCE_STATE_RENDER_TARGET)
|
||||
{
|
||||
texture->TransitionSubresourceToState(cmdlist, dst_level, texture->GetResourceState(),
|
||||
D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
}
|
||||
|
||||
const D3D12_RENDER_PASS_RENDER_TARGET_DESC rt_desc = {.cpuDescriptor = rtv_handle,
|
||||
.BeginningAccess =
|
||||
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_DISCARD,
|
||||
.EndingAccess = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE};
|
||||
cmdlist->BeginRenderPass(1, &rt_desc, nullptr, D3D12_RENDER_PASS_FLAG_NONE);
|
||||
|
||||
const D3D12_VIEWPORT vp = {0.0f, 0.0f, static_cast<float>(dst_width), static_cast<float>(dst_height), 0.0f, 1.0f};
|
||||
cmdlist->RSSetViewports(1, &vp);
|
||||
|
||||
const D3D12_RECT scissor = {0, 0, static_cast<LONG>(dst_width), static_cast<LONG>(dst_height)};
|
||||
cmdlist->RSSetScissorRects(1, &scissor);
|
||||
|
||||
cmdlist->SetPipelineState(pipeline.Get());
|
||||
cmdlist->SetGraphicsRootDescriptorTable(0, srv_handle);
|
||||
cmdlist->SetGraphicsRootDescriptorTable(1, static_cast<D3D12Sampler*>(m_linear_sampler.get())->GetDescriptor());
|
||||
cmdlist->DrawInstanced(3, 1, 0, 0);
|
||||
|
||||
cmdlist->EndRenderPass();
|
||||
|
||||
if (texture->GetResourceState() != D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE)
|
||||
{
|
||||
texture->TransitionSubresourceToState(cmdlist, src_level, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
|
||||
texture->GetResourceState());
|
||||
}
|
||||
if (texture->GetResourceState() != D3D12_RESOURCE_STATE_RENDER_TARGET)
|
||||
{
|
||||
texture->TransitionSubresourceToState(cmdlist, dst_level, D3D12_RESOURCE_STATE_RENDER_TARGET,
|
||||
texture->GetResourceState());
|
||||
}
|
||||
|
||||
// Must destroy after current cmdlist.
|
||||
DeferDescriptorDestruction(m_descriptor_heap_manager, &srv_handle);
|
||||
DeferDescriptorDestruction(m_rtv_heap_manager, &rtv_handle);
|
||||
|
||||
// Restore for next normal draw.
|
||||
SetViewport(GetCommandList());
|
||||
SetScissor(GetCommandList());
|
||||
m_dirty_flags |= LAYOUT_DEPENDENT_DIRTY_STATE;
|
||||
}
|
||||
|
||||
void D3D12Device::SetViewport(const GSVector4i rc)
|
||||
{
|
||||
if (m_current_viewport.eq(rc))
|
||||
|
|
|
@ -71,15 +71,18 @@ public:
|
|||
std::optional<bool> exclusive_fullscreen_control,
|
||||
Error* error) override;
|
||||
std::unique_ptr<GPUTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||
GPUTexture::Type type, GPUTexture::Format format,
|
||||
const void* data = nullptr, u32 data_stride = 0) override;
|
||||
std::unique_ptr<GPUSampler> CreateSampler(const GPUSampler::Config& config) override;
|
||||
std::unique_ptr<GPUTextureBuffer> CreateTextureBuffer(GPUTextureBuffer::Format format, u32 size_in_elements) override;
|
||||
GPUTexture::Type type, GPUTexture::Format format, GPUTexture::Flags flags,
|
||||
const void* data = nullptr, u32 data_stride = 0,
|
||||
Error* error = nullptr) override;
|
||||
std::unique_ptr<GPUSampler> CreateSampler(const GPUSampler::Config& config, Error* error = nullptr) override;
|
||||
std::unique_ptr<GPUTextureBuffer> CreateTextureBuffer(GPUTextureBuffer::Format format, u32 size_in_elements,
|
||||
Error* error = nullptr) override;
|
||||
|
||||
std::unique_ptr<GPUDownloadTexture> CreateDownloadTexture(u32 width, u32 height, GPUTexture::Format format) override;
|
||||
std::unique_ptr<GPUDownloadTexture> CreateDownloadTexture(u32 width, u32 height, GPUTexture::Format format,
|
||||
void* memory, size_t memory_size,
|
||||
u32 memory_stride) override;
|
||||
Error* error = nullptr) override;
|
||||
std::unique_ptr<GPUDownloadTexture> CreateDownloadTexture(u32 width, u32 height, GPUTexture::Format format,
|
||||
void* memory, size_t memory_size, u32 memory_stride,
|
||||
Error* error = nullptr) override;
|
||||
|
||||
bool SupportsTextureFormat(GPUTexture::Format format) const override;
|
||||
void CopyTextureRegion(GPUTexture* dst, u32 dst_x, u32 dst_y, u32 dst_layer, u32 dst_level, GPUTexture* src,
|
||||
|
@ -191,6 +194,9 @@ public:
|
|||
void UnbindTexture(D3D12Texture* tex);
|
||||
void UnbindTextureBuffer(D3D12TextureBuffer* buf);
|
||||
|
||||
void RenderTextureMipmap(D3D12Texture* texture, u32 dst_level, u32 dst_width, u32 dst_height, u32 src_level,
|
||||
u32 src_width, u32 src_height);
|
||||
|
||||
protected:
|
||||
bool CreateDeviceAndMainSwapChain(std::string_view adapter, FeatureMask disabled_features, const WindowInfo& wi,
|
||||
GPUVSyncMode vsync_mode, bool allow_present_throttle,
|
||||
|
@ -253,7 +259,7 @@ private:
|
|||
void DestroyDescriptorHeaps();
|
||||
bool CreateTimestampQuery();
|
||||
void DestroyTimestampQuery();
|
||||
D3D12DescriptorHandle GetSampler(const GPUSampler::Config& config);
|
||||
D3D12DescriptorHandle GetSampler(const GPUSampler::Config& config, Error* error);
|
||||
void DestroySamplers();
|
||||
void DestroyDeferredObjects(u64 fence_value);
|
||||
|
||||
|
@ -261,10 +267,13 @@ private:
|
|||
void MoveToNextCommandList();
|
||||
|
||||
bool CreateSRVDescriptor(ID3D12Resource* resource, u32 layers, u32 levels, u32 samples, DXGI_FORMAT format,
|
||||
D3D12DescriptorHandle* dh);
|
||||
bool CreateRTVDescriptor(ID3D12Resource* resource, u32 samples, DXGI_FORMAT format, D3D12DescriptorHandle* dh);
|
||||
bool CreateDSVDescriptor(ID3D12Resource* resource, u32 samples, DXGI_FORMAT format, D3D12DescriptorHandle* dh);
|
||||
bool CreateUAVDescriptor(ID3D12Resource* resource, u32 samples, DXGI_FORMAT format, D3D12DescriptorHandle* dh);
|
||||
D3D12DescriptorHandle* dh, Error* error);
|
||||
bool CreateRTVDescriptor(ID3D12Resource* resource, u32 samples, DXGI_FORMAT format, D3D12DescriptorHandle* dh,
|
||||
Error* error);
|
||||
bool CreateDSVDescriptor(ID3D12Resource* resource, u32 samples, DXGI_FORMAT format, D3D12DescriptorHandle* dh,
|
||||
Error* error);
|
||||
bool CreateUAVDescriptor(ID3D12Resource* resource, u32 samples, DXGI_FORMAT format, D3D12DescriptorHandle* dh,
|
||||
Error* error);
|
||||
|
||||
bool IsRenderTargetBound(const GPUTexture* tex) const;
|
||||
|
||||
|
@ -354,6 +363,9 @@ private:
|
|||
GSVector4i m_current_scissor = {};
|
||||
|
||||
D3D12SwapChain* m_current_swap_chain = nullptr;
|
||||
|
||||
std::array<ComPtr<ID3D12PipelineState>, static_cast<size_t>(GPUTexture::Format::MaxCount)> m_mipmap_render_pipelines =
|
||||
{};
|
||||
};
|
||||
|
||||
class D3D12SwapChain : public GPUSwapChain
|
||||
|
|
|
@ -18,12 +18,12 @@
|
|||
LOG_CHANNEL(GPUDevice);
|
||||
|
||||
D3D12Texture::D3D12Texture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, Type type, Format format,
|
||||
DXGI_FORMAT dxgi_format, ComPtr<ID3D12Resource> resource,
|
||||
Flags flags, DXGI_FORMAT dxgi_format, ComPtr<ID3D12Resource> resource,
|
||||
ComPtr<D3D12MA::Allocation> allocation, const D3D12DescriptorHandle& srv_descriptor,
|
||||
const D3D12DescriptorHandle& write_descriptor, const D3D12DescriptorHandle& uav_descriptor,
|
||||
WriteDescriptorType wdtype, D3D12_RESOURCE_STATES resource_state)
|
||||
: GPUTexture(static_cast<u16>(width), static_cast<u16>(height), static_cast<u8>(layers), static_cast<u8>(levels),
|
||||
static_cast<u8>(samples), type, format),
|
||||
static_cast<u8>(samples), type, format, flags),
|
||||
m_resource(std::move(resource)), m_allocation(std::move(allocation)), m_srv_descriptor(srv_descriptor),
|
||||
m_write_descriptor(write_descriptor), m_uav_descriptor(uav_descriptor), m_dxgi_format(dxgi_format),
|
||||
m_resource_state(resource_state), m_write_descriptor_type(wdtype)
|
||||
|
@ -37,9 +37,10 @@ D3D12Texture::~D3D12Texture()
|
|||
|
||||
std::unique_ptr<GPUTexture> D3D12Device::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||
GPUTexture::Type type, GPUTexture::Format format,
|
||||
const void* data /* = nullptr */, u32 data_stride /* = 0 */)
|
||||
GPUTexture::Flags flags, const void* data /* = nullptr */,
|
||||
u32 data_stride /* = 0 */, Error* error /* = nullptr */)
|
||||
{
|
||||
if (!GPUTexture::ValidateConfig(width, height, layers, levels, samples, type, format))
|
||||
if (!GPUTexture::ValidateConfig(width, height, layers, levels, samples, type, format, flags, error))
|
||||
return {};
|
||||
|
||||
const D3DCommon::DXGIFormatMapping& fm = D3DCommon::GetFormatMapping(format);
|
||||
|
@ -64,7 +65,6 @@ std::unique_ptr<GPUTexture> D3D12Device::CreateTexture(u32 width, u32 height, u3
|
|||
switch (type)
|
||||
{
|
||||
case GPUTexture::Type::Texture:
|
||||
case GPUTexture::Type::DynamicTexture:
|
||||
{
|
||||
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
||||
state = D3D12_RESOURCE_STATE_COPY_DEST;
|
||||
|
@ -92,18 +92,20 @@ std::unique_ptr<GPUTexture> D3D12Device::CreateTexture(u32 width, u32 height, u3
|
|||
}
|
||||
break;
|
||||
|
||||
case GPUTexture::Type::RWTexture:
|
||||
DefaultCaseIsUnreachable();
|
||||
}
|
||||
|
||||
if ((flags & GPUTexture::Flags::AllowBindAsImage) != GPUTexture::Flags::None)
|
||||
{
|
||||
DebugAssert(levels == 1);
|
||||
allocationDesc.Flags |= D3D12MA::ALLOCATION_FLAG_COMMITTED;
|
||||
desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
|
||||
optimized_clear_value.Format = fm.rtv_format;
|
||||
state = D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
|
||||
desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return {};
|
||||
if ((flags & GPUTexture::Flags::AllowGenerateMipmaps) != GPUTexture::Flags::None)
|
||||
{
|
||||
// requires RTs since we need to draw the mips
|
||||
desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
|
||||
}
|
||||
|
||||
ComPtr<ID3D12Resource> resource;
|
||||
|
@ -115,10 +117,7 @@ std::unique_ptr<GPUTexture> D3D12Device::CreateTexture(u32 width, u32 height, u3
|
|||
allocation.GetAddressOf(), IID_PPV_ARGS(resource.GetAddressOf()));
|
||||
if (FAILED(hr)) [[unlikely]]
|
||||
{
|
||||
// OOM isn't fatal.
|
||||
if (hr != E_OUTOFMEMORY)
|
||||
ERROR_LOG("Create texture failed: 0x{:08X}", static_cast<unsigned>(hr));
|
||||
|
||||
Error::SetHResult(error, "CreateResource() failed: ", hr);
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -126,16 +125,19 @@ std::unique_ptr<GPUTexture> D3D12Device::CreateTexture(u32 width, u32 height, u3
|
|||
D3D12Texture::WriteDescriptorType write_descriptor_type = D3D12Texture::WriteDescriptorType::None;
|
||||
if (fm.srv_format != DXGI_FORMAT_UNKNOWN)
|
||||
{
|
||||
if (!CreateSRVDescriptor(resource.Get(), layers, levels, samples, fm.srv_format, &srv_descriptor))
|
||||
if (!CreateSRVDescriptor(resource.Get(), layers, levels, samples, fm.srv_format, &srv_descriptor, error))
|
||||
return {};
|
||||
}
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case GPUTexture::Type::Texture:
|
||||
break;
|
||||
|
||||
case GPUTexture::Type::RenderTarget:
|
||||
{
|
||||
write_descriptor_type = D3D12Texture::WriteDescriptorType::RTV;
|
||||
if (!CreateRTVDescriptor(resource.Get(), samples, fm.rtv_format, &write_descriptor))
|
||||
if (!CreateRTVDescriptor(resource.Get(), samples, fm.rtv_format, &write_descriptor, error))
|
||||
{
|
||||
m_descriptor_heap_manager.Free(&srv_descriptor);
|
||||
return {};
|
||||
|
@ -146,7 +148,7 @@ std::unique_ptr<GPUTexture> D3D12Device::CreateTexture(u32 width, u32 height, u3
|
|||
case GPUTexture::Type::DepthStencil:
|
||||
{
|
||||
write_descriptor_type = D3D12Texture::WriteDescriptorType::DSV;
|
||||
if (!CreateDSVDescriptor(resource.Get(), samples, fm.dsv_format, &write_descriptor))
|
||||
if (!CreateDSVDescriptor(resource.Get(), samples, fm.dsv_format, &write_descriptor, error))
|
||||
{
|
||||
m_descriptor_heap_manager.Free(&srv_descriptor);
|
||||
return {};
|
||||
|
@ -154,30 +156,23 @@ std::unique_ptr<GPUTexture> D3D12Device::CreateTexture(u32 width, u32 height, u3
|
|||
}
|
||||
break;
|
||||
|
||||
case GPUTexture::Type::RWTexture:
|
||||
{
|
||||
write_descriptor_type = D3D12Texture::WriteDescriptorType::RTV;
|
||||
if (!CreateRTVDescriptor(resource.Get(), samples, fm.rtv_format, &write_descriptor))
|
||||
{
|
||||
m_descriptor_heap_manager.Free(&srv_descriptor);
|
||||
return {};
|
||||
DefaultCaseIsUnreachable();
|
||||
}
|
||||
|
||||
if (!CreateUAVDescriptor(resource.Get(), samples, fm.srv_format, &uav_descriptor))
|
||||
if ((flags & GPUTexture::Flags::AllowBindAsImage) != GPUTexture::Flags::None)
|
||||
{
|
||||
if (!CreateUAVDescriptor(resource.Get(), samples, fm.srv_format, &uav_descriptor, error))
|
||||
{
|
||||
if (write_descriptor_type != D3D12Texture::WriteDescriptorType::None)
|
||||
m_descriptor_heap_manager.Free(&write_descriptor);
|
||||
|
||||
m_descriptor_heap_manager.Free(&srv_descriptor);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
std::unique_ptr<D3D12Texture> tex(new D3D12Texture(
|
||||
width, height, layers, levels, samples, type, format, fm.resource_format, std::move(resource),
|
||||
width, height, layers, levels, samples, type, format, flags, fm.resource_format, std::move(resource),
|
||||
std::move(allocation), srv_descriptor, write_descriptor, uav_descriptor, write_descriptor_type, state));
|
||||
|
||||
if (data)
|
||||
|
@ -190,11 +185,11 @@ std::unique_ptr<GPUTexture> D3D12Device::CreateTexture(u32 width, u32 height, u3
|
|||
}
|
||||
|
||||
bool D3D12Device::CreateSRVDescriptor(ID3D12Resource* resource, u32 layers, u32 levels, u32 samples, DXGI_FORMAT format,
|
||||
D3D12DescriptorHandle* dh)
|
||||
D3D12DescriptorHandle* dh, Error* error)
|
||||
{
|
||||
if (!m_descriptor_heap_manager.Allocate(dh))
|
||||
{
|
||||
ERROR_LOG("Failed to allocate SRV descriptor");
|
||||
Error::SetStringView(error, "Failed to allocate SRV descriptor");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -233,11 +228,11 @@ bool D3D12Device::CreateSRVDescriptor(ID3D12Resource* resource, u32 layers, u32
|
|||
}
|
||||
|
||||
bool D3D12Device::CreateRTVDescriptor(ID3D12Resource* resource, u32 samples, DXGI_FORMAT format,
|
||||
D3D12DescriptorHandle* dh)
|
||||
D3D12DescriptorHandle* dh, Error* error)
|
||||
{
|
||||
if (!m_rtv_heap_manager.Allocate(dh))
|
||||
{
|
||||
ERROR_LOG("Failed to allocate SRV descriptor");
|
||||
Error::SetStringView(error, "Failed to allocate SRV descriptor");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -248,11 +243,11 @@ bool D3D12Device::CreateRTVDescriptor(ID3D12Resource* resource, u32 samples, DXG
|
|||
}
|
||||
|
||||
bool D3D12Device::CreateDSVDescriptor(ID3D12Resource* resource, u32 samples, DXGI_FORMAT format,
|
||||
D3D12DescriptorHandle* dh)
|
||||
D3D12DescriptorHandle* dh, Error* error)
|
||||
{
|
||||
if (!m_dsv_heap_manager.Allocate(dh))
|
||||
{
|
||||
ERROR_LOG("Failed to allocate SRV descriptor");
|
||||
Error::SetStringView(error, "Failed to allocate SRV descriptor");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -263,11 +258,11 @@ bool D3D12Device::CreateDSVDescriptor(ID3D12Resource* resource, u32 samples, DXG
|
|||
}
|
||||
|
||||
bool D3D12Device::CreateUAVDescriptor(ID3D12Resource* resource, u32 samples, DXGI_FORMAT format,
|
||||
D3D12DescriptorHandle* dh)
|
||||
D3D12DescriptorHandle* dh, Error* error)
|
||||
{
|
||||
if (!m_descriptor_heap_manager.Allocate(dh))
|
||||
{
|
||||
ERROR_LOG("Failed to allocate UAV descriptor");
|
||||
Error::SetStringView(error, "Failed to allocate UAV descriptor");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -334,9 +329,9 @@ void D3D12Texture::Destroy(bool defer)
|
|||
ID3D12GraphicsCommandList4* D3D12Texture::GetCommandBufferForUpdate()
|
||||
{
|
||||
D3D12Device& dev = D3D12Device::GetInstance();
|
||||
if ((m_type != Type::Texture && m_type != Type::DynamicTexture) || m_use_fence_counter == dev.GetCurrentFenceValue())
|
||||
if (m_type != Type::Texture || m_use_fence_counter == dev.GetCurrentFenceValue())
|
||||
{
|
||||
// Console.WriteLn("Texture update within frame, can't use do beforehand");
|
||||
// DEV_LOG("Texture update within frame, can't use do beforehand");
|
||||
if (dev.InRenderPass())
|
||||
dev.EndRenderPass();
|
||||
return dev.GetCommandList();
|
||||
|
@ -562,6 +557,28 @@ void D3D12Texture::Unmap()
|
|||
m_map_level = 0;
|
||||
}
|
||||
|
||||
void D3D12Texture::GenerateMipmaps()
|
||||
{
|
||||
Panic("Not implemented");
|
||||
|
||||
for (u32 layer = 0; layer < m_layers; layer++)
|
||||
{
|
||||
for (u32 dst_level = 1; dst_level < m_levels; dst_level++)
|
||||
{
|
||||
const u32 src_level = dst_level - 1;
|
||||
const u32 src_width = std::max<u32>(m_width >> src_level, 1u);
|
||||
const u32 src_height = std::max<u32>(m_height >> src_level, 1u);
|
||||
const u32 dst_width = std::max<u32>(m_width >> dst_level, 1u);
|
||||
const u32 dst_height = std::max<u32>(m_height >> dst_level, 1u);
|
||||
|
||||
D3D12Device::GetInstance().RenderTextureMipmap(this, dst_level, dst_width, dst_height, src_level, src_width,
|
||||
src_height);
|
||||
}
|
||||
}
|
||||
|
||||
SetUseFenceValue(D3D12Device::GetInstance().GetCurrentFenceValue());
|
||||
}
|
||||
|
||||
void D3D12Texture::CommitClear()
|
||||
{
|
||||
if (m_state != GPUTexture::State::Cleared)
|
||||
|
@ -685,7 +702,7 @@ void D3D12Sampler::SetDebugName(std::string_view name)
|
|||
{
|
||||
}
|
||||
|
||||
D3D12DescriptorHandle D3D12Device::GetSampler(const GPUSampler::Config& config)
|
||||
D3D12DescriptorHandle D3D12Device::GetSampler(const GPUSampler::Config& config, Error* error)
|
||||
{
|
||||
const auto it = m_sampler_map.find(config.key);
|
||||
if (it != m_sampler_map.end())
|
||||
|
@ -730,8 +747,10 @@ D3D12DescriptorHandle D3D12Device::GetSampler(const GPUSampler::Config& config)
|
|||
}
|
||||
|
||||
D3D12DescriptorHandle handle;
|
||||
if (m_sampler_heap_manager.Allocate(&handle))
|
||||
if (m_sampler_heap_manager.Allocate(&handle)) [[likely]]
|
||||
m_device->CreateSampler(&desc, handle);
|
||||
else
|
||||
Error::SetStringView(error, "Failed to allocate sampler handle.");
|
||||
|
||||
m_sampler_map.emplace(config.key, handle);
|
||||
return handle;
|
||||
|
@ -747,9 +766,9 @@ void D3D12Device::DestroySamplers()
|
|||
m_sampler_map.clear();
|
||||
}
|
||||
|
||||
std::unique_ptr<GPUSampler> D3D12Device::CreateSampler(const GPUSampler::Config& config)
|
||||
std::unique_ptr<GPUSampler> D3D12Device::CreateSampler(const GPUSampler::Config& config, Error* error /* = nullptr */)
|
||||
{
|
||||
const D3D12DescriptorHandle handle = GetSampler(config);
|
||||
const D3D12DescriptorHandle handle = GetSampler(config, error);
|
||||
if (!handle)
|
||||
return {};
|
||||
|
||||
|
@ -765,21 +784,20 @@ D3D12TextureBuffer::~D3D12TextureBuffer()
|
|||
Destroy(true);
|
||||
}
|
||||
|
||||
bool D3D12TextureBuffer::Create(D3D12Device& dev)
|
||||
bool D3D12TextureBuffer::Create(D3D12Device& dev, Error* error)
|
||||
{
|
||||
static constexpr std::array<DXGI_FORMAT, static_cast<u8>(GPUTextureBuffer::Format::MaxCount)> format_mapping = {{
|
||||
DXGI_FORMAT_R16_UINT, // R16UI
|
||||
}};
|
||||
|
||||
Error error;
|
||||
if (!m_buffer.Create(GetSizeInBytes(), &error)) [[unlikely]]
|
||||
{
|
||||
ERROR_LOG("Failed to create stream buffer: {}", error.GetDescription());
|
||||
if (!m_buffer.Create(GetSizeInBytes(), error)) [[unlikely]]
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!dev.GetDescriptorHeapManager().Allocate(&m_descriptor)) [[unlikely]]
|
||||
{
|
||||
Error::SetStringView(error, "Failed to allocate descriptor.");
|
||||
return {};
|
||||
}
|
||||
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC desc = {format_mapping[static_cast<u8>(m_format)],
|
||||
D3D12_SRV_DIMENSION_BUFFER,
|
||||
|
@ -831,11 +849,11 @@ void D3D12TextureBuffer::SetDebugName(std::string_view name)
|
|||
}
|
||||
|
||||
std::unique_ptr<GPUTextureBuffer> D3D12Device::CreateTextureBuffer(GPUTextureBuffer::Format format,
|
||||
u32 size_in_elements)
|
||||
u32 size_in_elements, Error* error /* = nullptr */)
|
||||
{
|
||||
|
||||
std::unique_ptr<D3D12TextureBuffer> tb = std::make_unique<D3D12TextureBuffer>(format, size_in_elements);
|
||||
if (!tb->Create(*this))
|
||||
if (!tb->Create(*this, error))
|
||||
tb.reset();
|
||||
|
||||
return tb;
|
||||
|
@ -858,7 +876,8 @@ D3D12DownloadTexture::~D3D12DownloadTexture()
|
|||
D3D12Device::GetInstance().DeferResourceDestruction(m_allocation.Get(), m_buffer.Get());
|
||||
}
|
||||
|
||||
std::unique_ptr<D3D12DownloadTexture> D3D12DownloadTexture::Create(u32 width, u32 height, GPUTexture::Format format)
|
||||
std::unique_ptr<D3D12DownloadTexture> D3D12DownloadTexture::Create(u32 width, u32 height, GPUTexture::Format format,
|
||||
Error* error)
|
||||
{
|
||||
const u32 buffer_size = GetBufferSize(width, height, format, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
|
||||
|
||||
|
@ -879,12 +898,12 @@ std::unique_ptr<D3D12DownloadTexture> D3D12DownloadTexture::Create(u32 width, u3
|
|||
ComPtr<D3D12MA::Allocation> allocation;
|
||||
ComPtr<ID3D12Resource> buffer;
|
||||
|
||||
HRESULT hr = D3D12Device::GetInstance().GetAllocator()->CreateResource(
|
||||
const HRESULT hr = D3D12Device::GetInstance().GetAllocator()->CreateResource(
|
||||
&allocation_desc, &resource_desc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, allocation.GetAddressOf(),
|
||||
IID_PPV_ARGS(buffer.GetAddressOf()));
|
||||
if (FAILED(hr))
|
||||
{
|
||||
ERROR_LOG("CreateResource() failed with HRESULT {:08X}", hr);
|
||||
Error::SetHResult(error, "CreateResource() failed: ", hr);
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -1015,15 +1034,16 @@ void D3D12DownloadTexture::SetDebugName(std::string_view name)
|
|||
D3D12::SetObjectName(m_buffer.Get(), name);
|
||||
}
|
||||
|
||||
std::unique_ptr<GPUDownloadTexture> D3D12Device::CreateDownloadTexture(u32 width, u32 height, GPUTexture::Format format)
|
||||
std::unique_ptr<GPUDownloadTexture> D3D12Device::CreateDownloadTexture(u32 width, u32 height, GPUTexture::Format format,
|
||||
Error* error /* = nullptr */)
|
||||
{
|
||||
return D3D12DownloadTexture::Create(width, height, format);
|
||||
return D3D12DownloadTexture::Create(width, height, format, error);
|
||||
}
|
||||
|
||||
std::unique_ptr<GPUDownloadTexture> D3D12Device::CreateDownloadTexture(u32 width, u32 height, GPUTexture::Format format,
|
||||
void* memory, size_t memory_size,
|
||||
u32 memory_stride)
|
||||
u32 memory_stride, Error* error /* = nullptr */)
|
||||
{
|
||||
ERROR_LOG("D3D12 cannot import memory for download textures");
|
||||
Error::SetStringView(error, "D3D12 cannot import memory for download textures");
|
||||
return {};
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ public:
|
|||
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;
|
||||
void Unmap() override;
|
||||
void GenerateMipmaps() override;
|
||||
void MakeReadyForSampling() override;
|
||||
|
||||
void SetDebugName(std::string_view name) override;
|
||||
|
@ -71,7 +72,7 @@ private:
|
|||
DSV
|
||||
};
|
||||
|
||||
D3D12Texture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, Type type, Format format,
|
||||
D3D12Texture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, Type type, Format format, Flags flags,
|
||||
DXGI_FORMAT dxgi_format, ComPtr<ID3D12Resource> resource, ComPtr<D3D12MA::Allocation> allocation,
|
||||
const D3D12DescriptorHandle& srv_descriptor, const D3D12DescriptorHandle& write_descriptor,
|
||||
const D3D12DescriptorHandle& uav_descriptor, WriteDescriptorType wdtype,
|
||||
|
@ -133,7 +134,7 @@ public:
|
|||
|
||||
ALWAYS_INLINE const D3D12DescriptorHandle& GetDescriptor() const { return m_descriptor; }
|
||||
|
||||
bool Create(D3D12Device& dev);
|
||||
bool Create(D3D12Device& dev, Error* error);
|
||||
void Destroy(bool defer);
|
||||
|
||||
// Inherited via GPUTextureBuffer
|
||||
|
@ -155,7 +156,7 @@ public:
|
|||
|
||||
~D3D12DownloadTexture() override;
|
||||
|
||||
static std::unique_ptr<D3D12DownloadTexture> Create(u32 width, u32 height, GPUTexture::Format format);
|
||||
static std::unique_ptr<D3D12DownloadTexture> Create(u32 width, u32 height, GPUTexture::Format format, Error* error);
|
||||
|
||||
void CopyFromTexture(u32 dst_x, u32 dst_y, GPUTexture* src, u32 src_x, u32 src_y, u32 width, u32 height,
|
||||
u32 src_layer, u32 src_level, bool use_transfer_pitch) override;
|
||||
|
|
|
@ -590,10 +590,10 @@ bool GPUDevice::GetPipelineCacheData(DynamicHeapArray<u8>* data, Error* error)
|
|||
|
||||
bool GPUDevice::CreateResources(Error* error)
|
||||
{
|
||||
if (!(m_nearest_sampler = CreateSampler(GPUSampler::GetNearestConfig())) ||
|
||||
!(m_linear_sampler = CreateSampler(GPUSampler::GetLinearConfig())))
|
||||
if (!(m_nearest_sampler = CreateSampler(GPUSampler::GetNearestConfig(), error)) ||
|
||||
!(m_linear_sampler = CreateSampler(GPUSampler::GetLinearConfig(), error)))
|
||||
{
|
||||
Error::SetStringView(error, "Failed to create samplers");
|
||||
Error::AddPrefix(error, "Failed to create samplers: ");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -922,10 +922,15 @@ bool GPUDevice::UpdateImGuiFontTexture()
|
|||
return true;
|
||||
}
|
||||
|
||||
Error error;
|
||||
std::unique_ptr<GPUTexture> new_font =
|
||||
FetchTexture(width, height, 1, 1, 1, GPUTexture::Type::Texture, GPUTexture::Format::RGBA8, pixels, pitch);
|
||||
if (!new_font)
|
||||
FetchTexture(width, height, 1, 1, 1, GPUTexture::Type::Texture, GPUTexture::Format::RGBA8, GPUTexture::Flags::None,
|
||||
pixels, pitch, &error);
|
||||
if (!new_font) [[unlikely]]
|
||||
{
|
||||
ERROR_LOG("Failed to create new ImGui font texture: {}", error.GetDescription());
|
||||
return false;
|
||||
}
|
||||
|
||||
RecycleTexture(std::move(m_imgui_font_texture));
|
||||
m_imgui_font_texture = std::move(new_font);
|
||||
|
@ -950,12 +955,13 @@ GSVector4i GPUDevice::FlipToLowerLeft(GSVector4i rc, s32 target_height)
|
|||
|
||||
bool GPUDevice::IsTexturePoolType(GPUTexture::Type type)
|
||||
{
|
||||
return (type == GPUTexture::Type::Texture || type == GPUTexture::Type::DynamicTexture);
|
||||
return (type == GPUTexture::Type::Texture);
|
||||
}
|
||||
|
||||
std::unique_ptr<GPUTexture> GPUDevice::FetchTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||
GPUTexture::Type type, GPUTexture::Format format,
|
||||
const void* data /*= nullptr*/, u32 data_stride /*= 0*/)
|
||||
GPUTexture::Flags flags, const void* data /* = nullptr */,
|
||||
u32 data_stride /* = 0 */, Error* error /* = nullptr */)
|
||||
{
|
||||
std::unique_ptr<GPUTexture> ret;
|
||||
|
||||
|
@ -966,7 +972,7 @@ std::unique_ptr<GPUTexture> GPUDevice::FetchTexture(u32 width, u32 height, u32 l
|
|||
static_cast<u8>(samples),
|
||||
type,
|
||||
format,
|
||||
0u};
|
||||
flags};
|
||||
|
||||
const bool is_texture = IsTexturePoolType(type);
|
||||
TexturePool& pool = is_texture ? m_texture_pool : m_target_pool;
|
||||
|
@ -1018,17 +1024,29 @@ std::unique_ptr<GPUTexture> GPUDevice::FetchTexture(u32 width, u32 height, u32 l
|
|||
}
|
||||
}
|
||||
|
||||
ret = CreateTexture(width, height, layers, levels, samples, type, format, data, data_stride);
|
||||
Error create_error;
|
||||
ret = CreateTexture(width, height, layers, levels, samples, type, format, flags, data, data_stride, &create_error);
|
||||
if (!ret) [[unlikely]]
|
||||
{
|
||||
Error::SetStringFmt(
|
||||
error ? error : &create_error, "Failed to create {}x{} {} {}: {}", width, height,
|
||||
GPUTexture::GetFormatName(format),
|
||||
((type == GPUTexture::Type::RenderTarget) ? "RT" : (type == GPUTexture::Type::DepthStencil ? "DS" : "Texture")),
|
||||
create_error.TakeDescription());
|
||||
if (!error)
|
||||
ERROR_LOG(create_error.GetDescription());
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::unique_ptr<GPUTexture, GPUDevice::PooledTextureDeleter>
|
||||
GPUDevice::FetchAutoRecycleTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, GPUTexture::Type type,
|
||||
GPUTexture::Format format, const void* data /*= nullptr*/, u32 data_stride /*= 0*/,
|
||||
bool dynamic /*= false*/)
|
||||
GPUTexture::Format format, GPUTexture::Flags flags, const void* data /* = nullptr */,
|
||||
u32 data_stride /* = 0 */, Error* error /* = nullptr */)
|
||||
{
|
||||
std::unique_ptr<GPUTexture> ret =
|
||||
FetchTexture(width, height, layers, levels, samples, type, format, data, data_stride);
|
||||
FetchTexture(width, height, layers, levels, samples, type, format, flags, data, data_stride, error);
|
||||
return std::unique_ptr<GPUTexture, PooledTextureDeleter>(ret.release());
|
||||
}
|
||||
|
||||
|
@ -1044,7 +1062,7 @@ void GPUDevice::RecycleTexture(std::unique_ptr<GPUTexture> texture)
|
|||
static_cast<u8>(texture->GetSamples()),
|
||||
texture->GetType(),
|
||||
texture->GetFormat(),
|
||||
0u};
|
||||
texture->GetFlags()};
|
||||
|
||||
const bool is_texture = IsTexturePoolType(texture->GetType());
|
||||
TexturePool& pool = is_texture ? m_texture_pool : m_target_pool;
|
||||
|
@ -1118,11 +1136,11 @@ void GPUDevice::TrimTexturePool()
|
|||
}
|
||||
|
||||
bool GPUDevice::ResizeTexture(std::unique_ptr<GPUTexture>* tex, u32 new_width, u32 new_height, GPUTexture::Type type,
|
||||
GPUTexture::Format format, bool preserve /* = true */)
|
||||
GPUTexture::Format format, GPUTexture::Flags flags, bool preserve /* = true */)
|
||||
{
|
||||
GPUTexture* old_tex = tex->get();
|
||||
DebugAssert(!old_tex || (old_tex->GetLayers() == 1 && old_tex->GetLevels() == 1 && old_tex->GetSamples() == 1));
|
||||
std::unique_ptr<GPUTexture> new_tex = FetchTexture(new_width, new_height, 1, 1, 1, type, format);
|
||||
std::unique_ptr<GPUTexture> new_tex = FetchTexture(new_width, new_height, 1, 1, 1, type, format, flags);
|
||||
if (!new_tex) [[unlikely]]
|
||||
{
|
||||
ERROR_LOG("Failed to create new {}x{} texture", new_width, new_height);
|
||||
|
|
|
@ -693,27 +693,28 @@ public:
|
|||
|
||||
virtual std::unique_ptr<GPUTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||
GPUTexture::Type type, GPUTexture::Format format,
|
||||
const void* data = nullptr, u32 data_stride = 0) = 0;
|
||||
virtual std::unique_ptr<GPUSampler> CreateSampler(const GPUSampler::Config& config) = 0;
|
||||
virtual std::unique_ptr<GPUTextureBuffer> CreateTextureBuffer(GPUTextureBuffer::Format format,
|
||||
u32 size_in_elements) = 0;
|
||||
GPUTexture::Flags flags, const void* data = nullptr,
|
||||
u32 data_stride = 0, Error* error = nullptr) = 0;
|
||||
virtual std::unique_ptr<GPUSampler> CreateSampler(const GPUSampler::Config& config, Error* error = nullptr) = 0;
|
||||
virtual std::unique_ptr<GPUTextureBuffer> CreateTextureBuffer(GPUTextureBuffer::Format format, u32 size_in_elements,
|
||||
Error* error = nullptr) = 0;
|
||||
|
||||
// Texture pooling.
|
||||
std::unique_ptr<GPUTexture> FetchTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||
GPUTexture::Type type, GPUTexture::Format format, const void* data = nullptr,
|
||||
u32 data_stride = 0);
|
||||
GPUTexture::Type type, GPUTexture::Format format, GPUTexture::Flags flags,
|
||||
const void* data = nullptr, u32 data_stride = 0, Error* error = nullptr);
|
||||
std::unique_ptr<GPUTexture, PooledTextureDeleter>
|
||||
FetchAutoRecycleTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, GPUTexture::Type type,
|
||||
GPUTexture::Format format, const void* data = nullptr, u32 data_stride = 0,
|
||||
bool dynamic = false);
|
||||
GPUTexture::Format format, GPUTexture::Flags flags, const void* data = nullptr,
|
||||
u32 data_stride = 0, Error* error = nullptr);
|
||||
void RecycleTexture(std::unique_ptr<GPUTexture> texture);
|
||||
void PurgeTexturePool();
|
||||
|
||||
virtual std::unique_ptr<GPUDownloadTexture> CreateDownloadTexture(u32 width, u32 height,
|
||||
GPUTexture::Format format) = 0;
|
||||
virtual std::unique_ptr<GPUDownloadTexture> CreateDownloadTexture(u32 width, u32 height, GPUTexture::Format format,
|
||||
void* memory, size_t memory_size,
|
||||
u32 memory_stride) = 0;
|
||||
Error* error = nullptr) = 0;
|
||||
virtual std::unique_ptr<GPUDownloadTexture> CreateDownloadTexture(u32 width, u32 height, GPUTexture::Format format,
|
||||
void* memory, size_t memory_size, u32 memory_stride,
|
||||
Error* error = nullptr) = 0;
|
||||
|
||||
virtual void CopyTextureRegion(GPUTexture* dst, u32 dst_x, u32 dst_y, u32 dst_layer, u32 dst_level, GPUTexture* src,
|
||||
u32 src_x, u32 src_y, u32 src_layer, u32 src_level, u32 width, u32 height) = 0;
|
||||
|
@ -789,7 +790,7 @@ public:
|
|||
bool UsesLowerLeftOrigin() const;
|
||||
static GSVector4i FlipToLowerLeft(GSVector4i rc, s32 target_height);
|
||||
bool ResizeTexture(std::unique_ptr<GPUTexture>* tex, u32 new_width, u32 new_height, GPUTexture::Type type,
|
||||
GPUTexture::Format format, bool preserve = true);
|
||||
GPUTexture::Format format, GPUTexture::Flags flags, bool preserve = true);
|
||||
|
||||
virtual bool SupportsTextureFormat(GPUTexture::Format format) const = 0;
|
||||
|
||||
|
@ -863,7 +864,7 @@ private:
|
|||
u8 samples;
|
||||
GPUTexture::Type type;
|
||||
GPUTexture::Format format;
|
||||
u8 pad;
|
||||
GPUTexture::Flags flags;
|
||||
|
||||
ALWAYS_INLINE bool operator==(const TexturePoolKey& rhs) const
|
||||
{
|
||||
|
|
|
@ -92,7 +92,7 @@ template<typename FBOType, FBOType (*FactoryFunc)(GPUTexture* const* rts, u32 nu
|
|||
void (*DestroyFunc)(FBOType fbo)>
|
||||
void GPUFramebufferManager<FBOType, FactoryFunc, DestroyFunc>::RemoveRTReferences(const GPUTexture* tex)
|
||||
{
|
||||
DebugAssert(tex->IsRenderTarget() || tex->IsRWTexture());
|
||||
DebugAssert(tex->IsRenderTarget());
|
||||
for (auto it = m_map.begin(); it != m_map.end();)
|
||||
{
|
||||
if (!it->first.ContainsRT(tex))
|
||||
|
|
|
@ -7,14 +7,12 @@
|
|||
#include "common/align.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/bitutils.h"
|
||||
#include "common/log.h"
|
||||
#include "common/error.h"
|
||||
#include "common/string_util.h"
|
||||
|
||||
LOG_CHANNEL(GPUTexture);
|
||||
|
||||
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, Flags flags)
|
||||
: m_width(width), m_height(height), m_layers(layers), m_levels(levels), m_samples(samples), m_type(type),
|
||||
m_format(format)
|
||||
m_format(format), m_flags(flags)
|
||||
{
|
||||
GPUDevice::s_total_vram_usage += GetVRAMUsage();
|
||||
}
|
||||
|
@ -119,6 +117,12 @@ u32 GPUTexture::CalcUploadSize(Format format, u32 height, u32 pitch)
|
|||
return pitch * ((static_cast<u32>(height) + (block_size - 1)) / block_size);
|
||||
}
|
||||
|
||||
u32 GPUTexture::GetFullMipmapCount(u32 width, u32 height)
|
||||
{
|
||||
const u32 max_dim = Common::PreviousPow2(std::max(width, height));
|
||||
return (std::countr_zero(max_dim) + 1);
|
||||
}
|
||||
|
||||
std::array<float, 4> GPUTexture::GetUNormClearColor() const
|
||||
{
|
||||
return GPUDevice::RGBA8ToFloat(m_clear_value.color);
|
||||
|
@ -192,25 +196,28 @@ bool GPUTexture::IsCompressedFormat(Format format)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool GPUTexture::ValidateConfig(u32 width, u32 height, u32 layers, u32 levels, u32 samples, Type type, Format format)
|
||||
bool GPUTexture::ValidateConfig(u32 width, u32 height, u32 layers, u32 levels, u32 samples, Type type, Format format,
|
||||
Flags flags, Error* error)
|
||||
{
|
||||
if (width > MAX_WIDTH || height > MAX_HEIGHT || layers > MAX_LAYERS || levels > MAX_LEVELS || samples > MAX_SAMPLES)
|
||||
if (width == 0 || width > MAX_WIDTH || height == 0 || height > MAX_HEIGHT || layers == 0 || layers > MAX_LAYERS ||
|
||||
levels == 0 || levels > MAX_LEVELS || samples == 0 || samples > MAX_SAMPLES)
|
||||
{
|
||||
ERROR_LOG("Invalid dimensions: {}x{}x{} {} {}.", width, height, layers, levels, samples);
|
||||
Error::SetStringFmt(error, "Invalid dimensions: {}x{}x{} {} {}.", width, height, layers, levels, samples);
|
||||
return false;
|
||||
}
|
||||
|
||||
const u32 max_texture_size = g_gpu_device->GetMaxTextureSize();
|
||||
if (width > max_texture_size || height > max_texture_size)
|
||||
{
|
||||
ERROR_LOG("Texture width ({}) or height ({}) exceeds max texture size ({}).", width, height, max_texture_size);
|
||||
Error::SetStringFmt(error, "Texture width ({}) or height ({}) exceeds max texture size ({}).", width, height,
|
||||
max_texture_size);
|
||||
return false;
|
||||
}
|
||||
|
||||
const u32 max_samples = g_gpu_device->GetMaxMultisamples();
|
||||
if (samples > max_samples)
|
||||
{
|
||||
ERROR_LOG("Texture samples ({}) exceeds max samples ({}).", samples, max_samples);
|
||||
Error::SetStringFmt(error, "Texture samples ({}) exceeds max samples ({}).", samples, max_samples);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -218,25 +225,45 @@ bool GPUTexture::ValidateConfig(u32 width, u32 height, u32 layers, u32 levels, u
|
|||
{
|
||||
if (levels > 1)
|
||||
{
|
||||
ERROR_LOG("Multisampled textures can't have mip levels.");
|
||||
Error::SetStringView(error, "Multisampled textures can't have mip levels.");
|
||||
return false;
|
||||
}
|
||||
else if (type != Type::RenderTarget && type != Type::DepthStencil)
|
||||
{
|
||||
ERROR_LOG("Multisampled textures must be render targets or depth stencil targets.");
|
||||
Error::SetStringView(error, "Multisampled textures must be render targets or depth stencil targets.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (layers > 1 && type != Type::Texture && type != Type::DynamicTexture)
|
||||
if (layers > 1 && type != Type::Texture)
|
||||
{
|
||||
ERROR_LOG("Texture arrays are not supported on targets.");
|
||||
Error::SetStringView(error, "Texture arrays are not supported on targets.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (levels > 1 && type != Type::Texture && type != Type::DynamicTexture)
|
||||
if (levels > 1 && type != Type::Texture)
|
||||
{
|
||||
ERROR_LOG("Mipmaps are not supported on targets.");
|
||||
Error::SetStringView(error, "Mipmaps are not supported on targets.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((flags & Flags::AllowGenerateMipmaps) != Flags::None && levels <= 1)
|
||||
{
|
||||
Error::SetStringView(error, "Allow generate mipmaps requires >1 level.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((flags & Flags::AllowBindAsImage) != Flags::None &&
|
||||
((type != Type::Texture && type != Type::RenderTarget) || levels > 1))
|
||||
{
|
||||
Error::SetStringView(error, "Bind as image is not allowed on depth or mipmapped targets.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((flags & Flags::AllowMap) != Flags::None &&
|
||||
(type != Type::Texture || (flags & Flags::AllowGenerateMipmaps) != Flags::None))
|
||||
{
|
||||
Error::SetStringView(error, "Allow map is not supported on targets.");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -331,7 +358,6 @@ bool GPUTexture::ConvertTextureDataToRGBA8(u32 width, u32 height, std::vector<u3
|
|||
}
|
||||
|
||||
default:
|
||||
[[unlikely]] ERROR_LOG("Unknown pixel format {}", static_cast<u32>(format));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
class Error;
|
||||
|
||||
class GPUTexture
|
||||
{
|
||||
public:
|
||||
|
@ -25,12 +27,9 @@ public:
|
|||
|
||||
enum class Type : u8
|
||||
{
|
||||
Unknown,
|
||||
Texture,
|
||||
RenderTarget,
|
||||
DepthStencil,
|
||||
Texture,
|
||||
DynamicTexture,
|
||||
RWTexture,
|
||||
};
|
||||
|
||||
enum class Format : u8
|
||||
|
@ -70,6 +69,15 @@ public:
|
|||
Invalidated
|
||||
};
|
||||
|
||||
enum class Flags : u8
|
||||
{
|
||||
None = 0,
|
||||
AllowMap = (1 << 0),
|
||||
AllowBindAsImage = (1 << 2),
|
||||
AllowGenerateMipmaps = (1 << 3),
|
||||
AllowMSAAResolveTarget = (1 << 4),
|
||||
};
|
||||
|
||||
union ClearValue
|
||||
{
|
||||
u32 color;
|
||||
|
@ -81,20 +89,22 @@ public:
|
|||
virtual ~GPUTexture();
|
||||
|
||||
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 u32 GetPixelSize(Format format);
|
||||
static bool IsDepthFormat(Format format);
|
||||
static bool IsDepthStencilFormat(Format format);
|
||||
static bool IsCompressedFormat(Format format);
|
||||
static u32 GetCompressedBytesPerBlock(Format format);
|
||||
static u32 GetCompressedBlockSize(Format format);
|
||||
static u32 CalcUploadPitch(Format format, u32 width);
|
||||
static u32 CalcUploadRowLengthFromPitch(Format format, u32 pitch);
|
||||
static u32 CalcUploadSize(Format format, u32 height, u32 pitch);
|
||||
static u32 GetFullMipmapCount(u32 width, u32 height);
|
||||
|
||||
static bool ValidateConfig(u32 width, u32 height, u32 layers, u32 levels, u32 samples, Type type, Format format);
|
||||
static bool ValidateConfig(u32 width, u32 height, u32 layers, u32 levels, u32 samples, Type type, Format format,
|
||||
Flags flags, Error* error);
|
||||
|
||||
static bool ConvertTextureDataToRGBA8(u32 width, u32 height, std::vector<u32>& texture_data, u32& texture_data_stride,
|
||||
GPUTexture::Format format);
|
||||
Format format);
|
||||
static void FlipTextureDataRGBA8(u32 width, u32 height, u8* texture_data, u32 texture_data_stride);
|
||||
|
||||
ALWAYS_INLINE u32 GetWidth() const { return m_width; }
|
||||
|
@ -104,6 +114,8 @@ public:
|
|||
ALWAYS_INLINE u32 GetSamples() const { return m_samples; }
|
||||
ALWAYS_INLINE Type GetType() const { return m_type; }
|
||||
ALWAYS_INLINE Format GetFormat() const { return m_format; }
|
||||
ALWAYS_INLINE Flags GetFlags() const { return m_flags; }
|
||||
ALWAYS_INLINE bool HasFlag(Flags flag) const { return ((static_cast<u8>(m_flags) & static_cast<u8>(flag)) != 0); }
|
||||
ALWAYS_INLINE GSVector4i GetRect() const
|
||||
{
|
||||
return GSVector4i(0, 0, static_cast<s32>(m_width), static_cast<s32>(m_height));
|
||||
|
@ -121,15 +133,13 @@ public:
|
|||
ALWAYS_INLINE bool IsDirty() const { return (m_state == State::Dirty); }
|
||||
ALWAYS_INLINE bool IsClearedOrInvalidated() const { return (m_state != State::Dirty); }
|
||||
|
||||
ALWAYS_INLINE bool IsTexture() const { return (m_type == Type::Texture); }
|
||||
ALWAYS_INLINE bool IsRenderTarget() const { return (m_type == Type::RenderTarget); }
|
||||
ALWAYS_INLINE bool IsDepthStencil() const { return (m_type == Type::DepthStencil); }
|
||||
ALWAYS_INLINE bool IsRenderTargetOrDepthStencil() const
|
||||
{
|
||||
return (m_type >= Type::RenderTarget && m_type <= Type::DepthStencil);
|
||||
}
|
||||
ALWAYS_INLINE bool IsRenderTarget() const { return (m_type == Type::RenderTarget); }
|
||||
ALWAYS_INLINE bool IsDepthStencil() const { return (m_type == Type::DepthStencil); }
|
||||
ALWAYS_INLINE bool IsTexture() const { return (m_type == Type::Texture || m_type == Type::DynamicTexture); }
|
||||
ALWAYS_INLINE bool IsDynamicTexture() const { return (m_type == Type::DynamicTexture); }
|
||||
ALWAYS_INLINE bool IsRWTexture() const { return (m_type == Type::RWTexture); }
|
||||
|
||||
ALWAYS_INLINE const ClearValue& GetClearValue() const { return m_clear_value; }
|
||||
ALWAYS_INLINE u32 GetClearColor() const { return m_clear_value.color; }
|
||||
|
@ -162,27 +172,32 @@ public:
|
|||
virtual bool Map(void** map, u32* map_stride, u32 x, u32 y, u32 width, u32 height, u32 layer = 0, u32 level = 0) = 0;
|
||||
virtual void Unmap() = 0;
|
||||
|
||||
virtual void GenerateMipmaps() = 0;
|
||||
|
||||
// Instructs the backend that we're finished rendering to this texture. It may transition it to a new layout.
|
||||
virtual void MakeReadyForSampling();
|
||||
|
||||
virtual void SetDebugName(std::string_view name) = 0;
|
||||
|
||||
protected:
|
||||
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, Flags flags);
|
||||
|
||||
u16 m_width = 0;
|
||||
u16 m_height = 0;
|
||||
u8 m_layers = 0;
|
||||
u8 m_levels = 0;
|
||||
u8 m_samples = 0;
|
||||
Type m_type = Type::Unknown;
|
||||
Type m_type = Type::Texture;
|
||||
Format m_format = Format::Unknown;
|
||||
Flags m_flags = Flags::None;
|
||||
|
||||
State m_state = State::Dirty;
|
||||
|
||||
ClearValue m_clear_value = {};
|
||||
};
|
||||
|
||||
IMPLEMENT_ENUM_CLASS_BITWISE_OPERATORS(GPUTexture::Flags);
|
||||
|
||||
class GPUDownloadTexture
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -290,9 +290,9 @@ const std::shared_ptr<GPUTexture>& ImGuiFullscreen::GetPlaceholderTexture()
|
|||
|
||||
std::unique_ptr<GPUTexture> ImGuiFullscreen::CreateTextureFromImage(const RGBA8Image& image)
|
||||
{
|
||||
std::unique_ptr<GPUTexture> ret =
|
||||
g_gpu_device->CreateTexture(image.GetWidth(), image.GetHeight(), 1, 1, 1, GPUTexture::Type::Texture,
|
||||
GPUTexture::Format::RGBA8, image.GetPixels(), image.GetPitch());
|
||||
std::unique_ptr<GPUTexture> ret = g_gpu_device->CreateTexture(
|
||||
image.GetWidth(), image.GetHeight(), 1, 1, 1, GPUTexture::Type::Texture, GPUTexture::Format::RGBA8,
|
||||
GPUTexture::Flags::None, image.GetPixels(), image.GetPitch());
|
||||
if (!ret) [[unlikely]]
|
||||
ERROR_LOG("Failed to upload {}x{} RGBA8Image to GPU", image.GetWidth(), image.GetHeight());
|
||||
return ret;
|
||||
|
@ -368,7 +368,7 @@ std::shared_ptr<GPUTexture> ImGuiFullscreen::UploadTexture(std::string_view path
|
|||
{
|
||||
std::unique_ptr<GPUTexture> texture =
|
||||
g_gpu_device->FetchTexture(image.GetWidth(), image.GetHeight(), 1, 1, 1, GPUTexture::Type::Texture,
|
||||
GPUTexture::Format::RGBA8, image.GetPixels(), image.GetPitch());
|
||||
GPUTexture::Format::RGBA8, GPUTexture::Flags::None, image.GetPixels(), image.GetPitch());
|
||||
if (!texture)
|
||||
{
|
||||
ERROR_LOG("Failed to create {}x{} texture for resource", image.GetWidth(), image.GetHeight());
|
||||
|
|
|
@ -1241,19 +1241,21 @@ void ImGuiManager::UpdateSoftwareCursorTexture(u32 index)
|
|||
return;
|
||||
}
|
||||
|
||||
Error error;
|
||||
RGBA8Image image;
|
||||
if (!image.LoadFromFile(sc.image_path.c_str()))
|
||||
if (!image.LoadFromFile(sc.image_path.c_str(), &error))
|
||||
{
|
||||
ERROR_LOG("Failed to load software cursor {} image '{}'", index, sc.image_path);
|
||||
ERROR_LOG("Failed to load software cursor {} image '{}': {}", index, sc.image_path, error.GetDescription());
|
||||
return;
|
||||
}
|
||||
g_gpu_device->RecycleTexture(std::move(sc.texture));
|
||||
sc.texture = g_gpu_device->FetchTexture(image.GetWidth(), image.GetHeight(), 1, 1, 1, GPUTexture::Type::Texture,
|
||||
GPUTexture::Format::RGBA8, image.GetPixels(), image.GetPitch());
|
||||
GPUTexture::Format::RGBA8, GPUTexture::Flags::None, image.GetPixels(),
|
||||
image.GetPitch(), &error);
|
||||
if (!sc.texture)
|
||||
{
|
||||
ERROR_LOG("Failed to upload {}x{} software cursor {} image '{}'", image.GetWidth(), image.GetHeight(), index,
|
||||
sc.image_path);
|
||||
ERROR_LOG("Failed to upload {}x{} software cursor {} image '{}': {}", image.GetWidth(), image.GetHeight(), index,
|
||||
sc.image_path, error.GetDescription());
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -244,7 +244,7 @@ GPUTexture* MediaCaptureBase::GetRenderTexture()
|
|||
return m_render_texture.get();
|
||||
|
||||
m_render_texture = g_gpu_device->CreateTexture(m_video_width, m_video_height, 1, 1, 1, GPUTexture::Type::RenderTarget,
|
||||
m_video_render_texture_format);
|
||||
m_video_render_texture_format, GPUTexture::Flags::None);
|
||||
if (!m_render_texture) [[unlikely]]
|
||||
{
|
||||
ERROR_LOG("Failed to create {}x{} render texture.", m_video_width, m_video_height);
|
||||
|
|
|
@ -120,6 +120,7 @@ public:
|
|||
void Unmap() override;
|
||||
|
||||
void MakeReadyForSampling() override;
|
||||
void GenerateMipmaps() override;
|
||||
|
||||
void SetDebugName(std::string_view name) override;
|
||||
|
||||
|
@ -128,7 +129,7 @@ public:
|
|||
|
||||
private:
|
||||
MetalTexture(id<MTLTexture> texture, u16 width, u16 height, u8 layers, u8 levels, u8 samples, Type type,
|
||||
Format format);
|
||||
Format format, Flags flags);
|
||||
|
||||
id<MTLTexture> m_texture;
|
||||
|
||||
|
@ -150,7 +151,7 @@ public:
|
|||
~MetalDownloadTexture() override;
|
||||
|
||||
static std::unique_ptr<MetalDownloadTexture> Create(u32 width, u32 height, GPUTexture::Format format, void* memory,
|
||||
size_t memory_size, u32 memory_stride);
|
||||
size_t memory_size, u32 memory_stride, Error* error);
|
||||
|
||||
void CopyFromTexture(u32 dst_x, u32 dst_y, GPUTexture* src, u32 src_x, u32 src_y, u32 width, u32 height,
|
||||
u32 src_layer, u32 src_level, bool use_transfer_pitch) override;
|
||||
|
@ -180,7 +181,7 @@ public:
|
|||
|
||||
ALWAYS_INLINE id<MTLBuffer> GetMTLBuffer() const { return m_buffer.GetBuffer(); }
|
||||
|
||||
bool CreateBuffer(id<MTLDevice> device);
|
||||
bool CreateBuffer(id<MTLDevice> device, Error* error);
|
||||
|
||||
// Inherited via GPUTextureBuffer
|
||||
void* Map(u32 required_elements) override;
|
||||
|
@ -234,15 +235,18 @@ public:
|
|||
std::optional<bool> exclusive_fullscreen_control,
|
||||
Error* error) override;
|
||||
std::unique_ptr<GPUTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||
GPUTexture::Type type, GPUTexture::Format format,
|
||||
const void* data = nullptr, u32 data_stride = 0) override;
|
||||
std::unique_ptr<GPUSampler> CreateSampler(const GPUSampler::Config& config) override;
|
||||
std::unique_ptr<GPUTextureBuffer> CreateTextureBuffer(GPUTextureBuffer::Format format, u32 size_in_elements) override;
|
||||
GPUTexture::Type type, GPUTexture::Format format, GPUTexture::Flags flags,
|
||||
const void* data = nullptr, u32 data_stride = 0,
|
||||
Error* error = nullptr) override;
|
||||
std::unique_ptr<GPUSampler> CreateSampler(const GPUSampler::Config& config, Error* error = nullptr) override;
|
||||
std::unique_ptr<GPUTextureBuffer> CreateTextureBuffer(GPUTextureBuffer::Format format, u32 size_in_elements,
|
||||
Error* error = nullptr) override;
|
||||
|
||||
std::unique_ptr<GPUDownloadTexture> CreateDownloadTexture(u32 width, u32 height, GPUTexture::Format format) override;
|
||||
std::unique_ptr<GPUDownloadTexture> CreateDownloadTexture(u32 width, u32 height, GPUTexture::Format format,
|
||||
void* memory, size_t memory_size,
|
||||
u32 memory_stride) override;
|
||||
Error* error = nullptr) override;
|
||||
std::unique_ptr<GPUDownloadTexture> CreateDownloadTexture(u32 width, u32 height, GPUTexture::Format format,
|
||||
void* memory, size_t memory_size, u32 memory_stride,
|
||||
Error* error = nullptr) override;
|
||||
|
||||
bool SupportsTextureFormat(GPUTexture::Format format) const override;
|
||||
void CopyTextureRegion(GPUTexture* dst, u32 dst_x, u32 dst_y, u32 dst_layer, u32 dst_level, GPUTexture* src,
|
||||
|
@ -325,7 +329,7 @@ private:
|
|||
static constexpr u32 INDEX_BUFFER_SIZE = 4 * 1024 * 1024;
|
||||
static constexpr u32 UNIFORM_BUFFER_SIZE = 2 * 1024 * 1024;
|
||||
static constexpr u32 UNIFORM_BUFFER_ALIGNMENT = 256;
|
||||
static constexpr u32 TEXTURE_STREAM_BUFFER_SIZE = 32 /*16*/ * 1024 * 1024; // TODO reduce after separate allocations
|
||||
static constexpr u32 TEXTURE_STREAM_BUFFER_SIZE = 64 * 1024 * 1024; // TODO reduce after separate allocations
|
||||
static constexpr u8 NUM_TIMESTAMP_QUERIES = 3;
|
||||
|
||||
using DepthStateMap = std::unordered_map<u8, id<MTLDepthStencilState>>;
|
||||
|
@ -377,7 +381,7 @@ private:
|
|||
|
||||
void RenderBlankFrame(MetalSwapChain* swap_chain);
|
||||
|
||||
bool CreateBuffers();
|
||||
bool CreateBuffers(Error* error);
|
||||
void DestroyBuffers();
|
||||
|
||||
bool IsRenderTargetBound(const GPUTexture* tex) const;
|
||||
|
|
|
@ -347,11 +347,8 @@ bool MetalDevice::CreateDeviceAndMainSwapChain(std::string_view adapter, Feature
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!CreateBuffers())
|
||||
{
|
||||
Error::SetStringView(error, "Failed to create buffers.");
|
||||
if (!CreateBuffers(error))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -575,13 +572,14 @@ std::string MetalDevice::GetDriverInfo() const
|
|||
}
|
||||
}
|
||||
|
||||
bool MetalDevice::CreateBuffers()
|
||||
bool MetalDevice::CreateBuffers(Error* error)
|
||||
{
|
||||
if (!m_vertex_buffer.Create(m_device, VERTEX_BUFFER_SIZE) || !m_index_buffer.Create(m_device, INDEX_BUFFER_SIZE) ||
|
||||
!m_uniform_buffer.Create(m_device, UNIFORM_BUFFER_SIZE) ||
|
||||
!m_texture_upload_buffer.Create(m_device, TEXTURE_STREAM_BUFFER_SIZE))
|
||||
if (!m_vertex_buffer.Create(m_device, VERTEX_BUFFER_SIZE, error) ||
|
||||
!m_index_buffer.Create(m_device, INDEX_BUFFER_SIZE, error) ||
|
||||
!m_uniform_buffer.Create(m_device, UNIFORM_BUFFER_SIZE, error) ||
|
||||
!m_texture_upload_buffer.Create(m_device, TEXTURE_STREAM_BUFFER_SIZE, error))
|
||||
{
|
||||
ERROR_LOG("Failed to create vertex/index/uniform buffers.");
|
||||
Error::AddPrefix(error, "Failed to create vertex/index/uniform buffers: ");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -980,8 +978,8 @@ std::unique_ptr<GPUPipeline> MetalDevice::CreatePipeline(const GPUPipeline::Comp
|
|||
}
|
||||
|
||||
MetalTexture::MetalTexture(id<MTLTexture> texture, u16 width, u16 height, u8 layers, u8 levels, u8 samples, Type type,
|
||||
Format format)
|
||||
: GPUTexture(width, height, layers, levels, samples, type, format), m_texture(texture)
|
||||
Format format, Flags flags)
|
||||
: GPUTexture(width, height, layers, levels, samples, type, format, flags), m_texture(texture)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -1141,6 +1139,15 @@ void MetalTexture::MakeReadyForSampling()
|
|||
dev.EndRenderPass();
|
||||
}
|
||||
|
||||
void MetalTexture::GenerateMipmaps()
|
||||
{
|
||||
DebugAssert(HasFlag(Flags::AllowGenerateMipmaps));
|
||||
MetalDevice& dev = MetalDevice::GetInstance();
|
||||
const bool is_inline = (m_use_fence_counter == dev.GetCurrentFenceCounter());
|
||||
id<MTLBlitCommandEncoder> encoder = dev.GetBlitEncoder(is_inline);
|
||||
[encoder generateMipmapsForTexture:m_texture];
|
||||
}
|
||||
|
||||
void MetalTexture::SetDebugName(std::string_view name)
|
||||
{
|
||||
@autoreleasepool
|
||||
|
@ -1151,14 +1158,18 @@ void MetalTexture::SetDebugName(std::string_view name)
|
|||
|
||||
std::unique_ptr<GPUTexture> MetalDevice::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||
GPUTexture::Type type, GPUTexture::Format format,
|
||||
const void* data, u32 data_stride)
|
||||
GPUTexture::Flags flags, const void* data, u32 data_stride,
|
||||
Error* error)
|
||||
{
|
||||
if (!GPUTexture::ValidateConfig(width, height, layers, layers, samples, type, format))
|
||||
if (!GPUTexture::ValidateConfig(width, height, layers, layers, samples, type, format, flags, error))
|
||||
return {};
|
||||
|
||||
const MTLPixelFormat pixel_format = s_pixel_format_mapping[static_cast<u8>(format)];
|
||||
if (pixel_format == MTLPixelFormatInvalid)
|
||||
{
|
||||
Error::SetStringFmt(error, "Pixel format {} is not supported.", GPUTexture::GetFormatName(format));
|
||||
return {};
|
||||
}
|
||||
|
||||
@autoreleasepool
|
||||
{
|
||||
|
@ -1183,7 +1194,6 @@ std::unique_ptr<GPUTexture> MetalDevice::CreateTexture(u32 width, u32 height, u3
|
|||
switch (type)
|
||||
{
|
||||
case GPUTexture::Type::Texture:
|
||||
case GPUTexture::Type::DynamicTexture:
|
||||
desc.usage = MTLTextureUsageShaderRead;
|
||||
break;
|
||||
|
||||
|
@ -1192,25 +1202,25 @@ std::unique_ptr<GPUTexture> MetalDevice::CreateTexture(u32 width, u32 height, u3
|
|||
desc.usage = MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget;
|
||||
break;
|
||||
|
||||
case GPUTexture::Type::RWTexture:
|
||||
desc.usage = MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite;
|
||||
break;
|
||||
DefaultCaseIsUnreachable();
|
||||
}
|
||||
|
||||
default:
|
||||
UnreachableCode();
|
||||
break;
|
||||
if ((flags & (GPUTexture::Flags::AllowBindAsImage | GPUTexture::Flags::AllowMSAAResolveTarget)) !=
|
||||
GPUTexture::Flags::None)
|
||||
{
|
||||
desc.usage |= MTLTextureUsageShaderWrite;
|
||||
}
|
||||
|
||||
id<MTLTexture> tex = [m_device newTextureWithDescriptor:desc];
|
||||
if (tex == nil)
|
||||
{
|
||||
ERROR_LOG("Failed to create {}x{} texture.", width, height);
|
||||
Error::SetStringView(error, "newTextureWithDescriptor() failed");
|
||||
return {};
|
||||
}
|
||||
|
||||
// This one can *definitely* go on the upload buffer.
|
||||
std::unique_ptr<GPUTexture> gtex(
|
||||
new MetalTexture([tex retain], width, height, layers, levels, samples, type, format));
|
||||
new MetalTexture([tex retain], width, height, layers, levels, samples, type, format, flags));
|
||||
if (data)
|
||||
{
|
||||
// TODO: handle multi-level uploads...
|
||||
|
@ -1236,7 +1246,8 @@ MetalDownloadTexture::~MetalDownloadTexture()
|
|||
}
|
||||
|
||||
std::unique_ptr<MetalDownloadTexture> MetalDownloadTexture::Create(u32 width, u32 height, GPUTexture::Format format,
|
||||
void* memory, size_t memory_size, u32 memory_stride)
|
||||
void* memory, size_t memory_size, u32 memory_stride,
|
||||
Error* error)
|
||||
{
|
||||
@autoreleasepool
|
||||
{
|
||||
|
@ -1257,7 +1268,7 @@ std::unique_ptr<MetalDownloadTexture> MetalDownloadTexture::Create(u32 width, u3
|
|||
buffer = [[dev.m_device newBufferWithLength:buffer_size options:options] retain];
|
||||
if (buffer == nil)
|
||||
{
|
||||
ERROR_LOG("Failed to create {} byte buffer", buffer_size);
|
||||
Error::SetStringFmt(error, "Failed to create {} byte buffer", buffer_size);
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -1282,7 +1293,7 @@ std::unique_ptr<MetalDownloadTexture> MetalDownloadTexture::Create(u32 width, u3
|
|||
deallocator:nil] retain];
|
||||
if (buffer == nil)
|
||||
{
|
||||
ERROR_LOG("Failed to import {} byte buffer", page_aligned_size);
|
||||
Error::SetStringFmt(error, "Failed to import {} byte buffer", page_aligned_size);
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -1369,16 +1380,17 @@ void MetalDownloadTexture::SetDebugName(std::string_view name)
|
|||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<GPUDownloadTexture> MetalDevice::CreateDownloadTexture(u32 width, u32 height, GPUTexture::Format format)
|
||||
std::unique_ptr<GPUDownloadTexture> MetalDevice::CreateDownloadTexture(u32 width, u32 height, GPUTexture::Format format,
|
||||
Error* error)
|
||||
{
|
||||
return MetalDownloadTexture::Create(width, height, format, nullptr, 0, 0);
|
||||
return MetalDownloadTexture::Create(width, height, format, nullptr, 0, 0, error);
|
||||
}
|
||||
|
||||
std::unique_ptr<GPUDownloadTexture> MetalDevice::CreateDownloadTexture(u32 width, u32 height, GPUTexture::Format format,
|
||||
void* memory, size_t memory_size,
|
||||
u32 memory_stride)
|
||||
u32 memory_stride, Error* error)
|
||||
{
|
||||
return MetalDownloadTexture::Create(width, height, format, memory, memory_size, memory_stride);
|
||||
return MetalDownloadTexture::Create(width, height, format, memory, memory_size, memory_stride, error);
|
||||
}
|
||||
|
||||
MetalSampler::MetalSampler(id<MTLSamplerState> ss) : m_ss(ss)
|
||||
|
@ -1392,7 +1404,7 @@ void MetalSampler::SetDebugName(std::string_view name)
|
|||
// lame.. have to put it on the descriptor :/
|
||||
}
|
||||
|
||||
std::unique_ptr<GPUSampler> MetalDevice::CreateSampler(const GPUSampler::Config& config)
|
||||
std::unique_ptr<GPUSampler> MetalDevice::CreateSampler(const GPUSampler::Config& config, Error* error)
|
||||
{
|
||||
@autoreleasepool
|
||||
{
|
||||
|
@ -1448,7 +1460,7 @@ std::unique_ptr<GPUSampler> MetalDevice::CreateSampler(const GPUSampler::Config&
|
|||
}
|
||||
if (i == std::size(border_color_mapping))
|
||||
{
|
||||
ERROR_LOG("Unsupported border color: {:08X}", config.border_color.GetValue());
|
||||
Error::SetStringFmt(error, "Unsupported border color: {:08X}", config.border_color.GetValue());
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -1459,7 +1471,7 @@ std::unique_ptr<GPUSampler> MetalDevice::CreateSampler(const GPUSampler::Config&
|
|||
id<MTLSamplerState> ss = [m_device newSamplerStateWithDescriptor:desc];
|
||||
if (ss == nil)
|
||||
{
|
||||
ERROR_LOG("Failed to create sampler state.");
|
||||
Error::SetStringView(error, "newSamplerStateWithDescriptor failed");
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -1550,6 +1562,7 @@ void MetalDevice::ResolveTextureRegion(GPUTexture* dst, u32 dst_x, u32 dst_y, u3
|
|||
DebugAssert((dst_x + width) <= dst->GetMipWidth(dst_level));
|
||||
DebugAssert((dst_y + height) <= dst->GetMipHeight(dst_level));
|
||||
DebugAssert(!dst->IsMultisampled() && src->IsMultisampled());
|
||||
DebugAssert(dst->HasFlag(GPUTexture::Flags::AllowMSAAResolveTarget));
|
||||
|
||||
// Only does first level for now..
|
||||
DebugAssert(dst_level == 0 && dst_layer == 0);
|
||||
|
@ -1767,9 +1780,9 @@ MetalTextureBuffer::~MetalTextureBuffer()
|
|||
m_buffer.Destroy();
|
||||
}
|
||||
|
||||
bool MetalTextureBuffer::CreateBuffer(id<MTLDevice> device)
|
||||
bool MetalTextureBuffer::CreateBuffer(id<MTLDevice> device, Error* error)
|
||||
{
|
||||
return m_buffer.Create(device, GetSizeInBytes());
|
||||
return m_buffer.Create(device, GetSizeInBytes(), error);
|
||||
}
|
||||
|
||||
void* MetalTextureBuffer::Map(u32 required_elements)
|
||||
|
@ -1804,10 +1817,10 @@ void MetalTextureBuffer::SetDebugName(std::string_view name)
|
|||
}
|
||||
|
||||
std::unique_ptr<GPUTextureBuffer> MetalDevice::CreateTextureBuffer(GPUTextureBuffer::Format format,
|
||||
u32 size_in_elements)
|
||||
u32 size_in_elements, Error* error)
|
||||
{
|
||||
std::unique_ptr<MetalTextureBuffer> tb = std::make_unique<MetalTextureBuffer>(format, size_in_elements);
|
||||
if (!tb->CreateBuffer(m_device))
|
||||
if (!tb->CreateBuffer(m_device, error))
|
||||
tb.reset();
|
||||
|
||||
return tb;
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
#include <deque>
|
||||
#include <memory>
|
||||
|
||||
class Error;
|
||||
|
||||
class MetalStreamBuffer
|
||||
{
|
||||
public:
|
||||
|
@ -38,7 +40,7 @@ public:
|
|||
ALWAYS_INLINE u32 GetCurrentSpace() const { return m_current_space; }
|
||||
ALWAYS_INLINE u32 GetCurrentOffset() const { return m_current_offset; }
|
||||
|
||||
bool Create(id<MTLDevice> device, u32 size);
|
||||
bool Create(id<MTLDevice> device, u32 size, Error* error);
|
||||
void Destroy();
|
||||
|
||||
bool ReserveMemory(u32 num_bytes, u32 alignment);
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "common/align.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/error.h"
|
||||
#include "common/log.h"
|
||||
|
||||
LOG_CHANNEL(GPUDevice);
|
||||
|
@ -18,7 +19,7 @@ MetalStreamBuffer::~MetalStreamBuffer()
|
|||
Destroy();
|
||||
}
|
||||
|
||||
bool MetalStreamBuffer::Create(id<MTLDevice> device, u32 size)
|
||||
bool MetalStreamBuffer::Create(id<MTLDevice> device, u32 size, Error* error)
|
||||
{
|
||||
@autoreleasepool
|
||||
{
|
||||
|
@ -27,7 +28,7 @@ bool MetalStreamBuffer::Create(id<MTLDevice> device, u32 size)
|
|||
id<MTLBuffer> new_buffer = [device newBufferWithLength:size options:options];
|
||||
if (new_buffer == nil)
|
||||
{
|
||||
ERROR_LOG("Failed to create buffer.");
|
||||
Error::SetStringView(error, "newBufferWithLength failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -60,9 +60,10 @@ void OpenGLDevice::SetErrorObject(Error* errptr, std::string_view prefix, GLenum
|
|||
|
||||
std::unique_ptr<GPUTexture> OpenGLDevice::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||
GPUTexture::Type type, GPUTexture::Format format,
|
||||
const void* data, u32 data_stride)
|
||||
GPUTexture::Flags flags, const void* data /* = nullptr */,
|
||||
u32 data_stride /* = 0 */, Error* error /* = nullptr */)
|
||||
{
|
||||
return OpenGLTexture::Create(width, height, layers, levels, samples, type, format, data, data_stride);
|
||||
return OpenGLTexture::Create(width, height, layers, levels, samples, type, format, flags, data, data_stride, error);
|
||||
}
|
||||
|
||||
bool OpenGLDevice::SupportsTextureFormat(GPUTexture::Format format) const
|
||||
|
|
|
@ -52,15 +52,18 @@ public:
|
|||
std::optional<bool> exclusive_fullscreen_control,
|
||||
Error* error) override;
|
||||
std::unique_ptr<GPUTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||
GPUTexture::Type type, GPUTexture::Format format,
|
||||
const void* data = nullptr, u32 data_stride = 0) override;
|
||||
std::unique_ptr<GPUSampler> CreateSampler(const GPUSampler::Config& config) override;
|
||||
std::unique_ptr<GPUTextureBuffer> CreateTextureBuffer(GPUTextureBuffer::Format format, u32 size_in_elements) override;
|
||||
GPUTexture::Type type, GPUTexture::Format format, GPUTexture::Flags flags,
|
||||
const void* data = nullptr, u32 data_stride = 0,
|
||||
Error* error = nullptr) override;
|
||||
std::unique_ptr<GPUSampler> CreateSampler(const GPUSampler::Config& config, Error* error = nullptr) override;
|
||||
std::unique_ptr<GPUTextureBuffer> CreateTextureBuffer(GPUTextureBuffer::Format format, u32 size_in_elements,
|
||||
Error* error = nullptr) override;
|
||||
|
||||
std::unique_ptr<GPUDownloadTexture> CreateDownloadTexture(u32 width, u32 height, GPUTexture::Format format) override;
|
||||
std::unique_ptr<GPUDownloadTexture> CreateDownloadTexture(u32 width, u32 height, GPUTexture::Format format,
|
||||
void* memory, size_t memory_size,
|
||||
u32 memory_stride) override;
|
||||
Error* error = nullptr) override;
|
||||
std::unique_ptr<GPUDownloadTexture> CreateDownloadTexture(u32 width, u32 height, GPUTexture::Format format,
|
||||
void* memory, size_t memory_size, u32 memory_stride,
|
||||
Error* error = nullptr) override;
|
||||
|
||||
bool SupportsTextureFormat(GPUTexture::Format format) const override;
|
||||
void CopyTextureRegion(GPUTexture* dst, u32 dst_x, u32 dst_y, u32 dst_layer, u32 dst_level, GPUTexture* src,
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
|
||||
#include "common/align.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/error.h"
|
||||
|
||||
#include <array>
|
||||
#include <cstdio>
|
||||
|
||||
OpenGLStreamBuffer::OpenGLStreamBuffer(GLenum target, GLuint buffer_id, u32 size)
|
||||
: m_target(target), m_buffer_id(buffer_id), m_size(size)
|
||||
|
@ -65,7 +65,7 @@ public:
|
|||
|
||||
u32 GetChunkSize() const override { return m_size; }
|
||||
|
||||
static std::unique_ptr<OpenGLStreamBuffer> Create(GLenum target, u32 size)
|
||||
static std::unique_ptr<OpenGLStreamBuffer> Create(GLenum target, u32 size, Error* error)
|
||||
{
|
||||
glGetError();
|
||||
|
||||
|
@ -74,9 +74,10 @@ public:
|
|||
glBindBuffer(target, buffer_id);
|
||||
glBufferData(target, size, nullptr, GL_STREAM_DRAW);
|
||||
|
||||
GLenum err = glGetError();
|
||||
if (err != GL_NO_ERROR)
|
||||
const GLenum err = glGetError();
|
||||
if (err != GL_NO_ERROR) [[unlikely]]
|
||||
{
|
||||
Error::SetStringFmt(error, "Failed to create buffer: 0x{:X}", err);
|
||||
glBindBuffer(target, 0);
|
||||
glDeleteBuffers(1, &buffer_id);
|
||||
return {};
|
||||
|
@ -119,7 +120,7 @@ public:
|
|||
|
||||
u32 GetChunkSize() const override { return m_size; }
|
||||
|
||||
static std::unique_ptr<OpenGLStreamBuffer> Create(GLenum target, u32 size)
|
||||
static std::unique_ptr<OpenGLStreamBuffer> Create(GLenum target, u32 size, Error* error)
|
||||
{
|
||||
glGetError();
|
||||
|
||||
|
@ -128,9 +129,10 @@ public:
|
|||
glBindBuffer(target, buffer_id);
|
||||
glBufferData(target, size, nullptr, GL_STREAM_DRAW);
|
||||
|
||||
GLenum err = glGetError();
|
||||
if (err != GL_NO_ERROR)
|
||||
const GLenum err = glGetError();
|
||||
if (err != GL_NO_ERROR) [[unlikely]]
|
||||
{
|
||||
Error::SetStringFmt(error, "Failed to create buffer: 0x{:X}", err);
|
||||
glBindBuffer(target, 0);
|
||||
glDeleteBuffers(1, &buffer_id);
|
||||
return {};
|
||||
|
@ -283,7 +285,7 @@ public:
|
|||
return prev_position;
|
||||
}
|
||||
|
||||
static std::unique_ptr<OpenGLStreamBuffer> Create(GLenum target, u32 size, bool coherent = true)
|
||||
static std::unique_ptr<OpenGLStreamBuffer> Create(GLenum target, u32 size, Error* error, bool coherent = true)
|
||||
{
|
||||
glGetError();
|
||||
|
||||
|
@ -298,9 +300,10 @@ public:
|
|||
else if (GLAD_GL_EXT_buffer_storage)
|
||||
glBufferStorageEXT(target, size, nullptr, flags);
|
||||
|
||||
GLenum err = glGetError();
|
||||
if (err != GL_NO_ERROR)
|
||||
const GLenum err = glGetError();
|
||||
if (err != GL_NO_ERROR) [[unlikely]]
|
||||
{
|
||||
Error::SetStringFmt(error, "Failed to create buffer: 0x{:X}", err);
|
||||
glBindBuffer(target, 0);
|
||||
glDeleteBuffers(1, &buffer_id);
|
||||
return {};
|
||||
|
@ -325,12 +328,12 @@ private:
|
|||
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<OpenGLStreamBuffer> OpenGLStreamBuffer::Create(GLenum target, u32 size)
|
||||
std::unique_ptr<OpenGLStreamBuffer> OpenGLStreamBuffer::Create(GLenum target, u32 size, Error* error /* = nullptr */)
|
||||
{
|
||||
std::unique_ptr<OpenGLStreamBuffer> buf;
|
||||
if (GLAD_GL_VERSION_4_4 || GLAD_GL_ARB_buffer_storage || GLAD_GL_EXT_buffer_storage)
|
||||
{
|
||||
buf = BufferStorageStreamBuffer::Create(target, size);
|
||||
buf = BufferStorageStreamBuffer::Create(target, size, error);
|
||||
if (buf)
|
||||
return buf;
|
||||
}
|
||||
|
@ -341,11 +344,11 @@ std::unique_ptr<OpenGLStreamBuffer> OpenGLStreamBuffer::Create(GLenum target, u3
|
|||
if (std::strcmp(vendor, "ARM") == 0 || std::strcmp(vendor, "Qualcomm") == 0)
|
||||
{
|
||||
// Mali and Adreno drivers can't do sub-buffer tracking...
|
||||
return BufferDataStreamBuffer::Create(target, size);
|
||||
return BufferDataStreamBuffer::Create(target, size, error);
|
||||
}
|
||||
|
||||
return BufferSubDataStreamBuffer::Create(target, size);
|
||||
return BufferSubDataStreamBuffer::Create(target, size, error);
|
||||
#else
|
||||
return BufferDataStreamBuffer::Create(target, size);
|
||||
return BufferDataStreamBuffer::Create(target, size, error);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
class Error;
|
||||
|
||||
class OpenGLStreamBuffer
|
||||
{
|
||||
public:
|
||||
|
@ -42,7 +44,7 @@ public:
|
|||
/// Returns the minimum granularity of blocks which sync objects will be created around.
|
||||
virtual u32 GetChunkSize() const = 0;
|
||||
|
||||
static std::unique_ptr<OpenGLStreamBuffer> Create(GLenum target, u32 size);
|
||||
static std::unique_ptr<OpenGLStreamBuffer> Create(GLenum target, u32 size, Error* error = nullptr);
|
||||
|
||||
protected:
|
||||
OpenGLStreamBuffer(GLenum target, GLuint buffer_id, u32 size);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include "common/align.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/error.h"
|
||||
#include "common/intrin.h"
|
||||
#include "common/log.h"
|
||||
#include "common/string_util.h"
|
||||
|
@ -98,9 +99,9 @@ ALWAYS_INLINE static u32 GetUploadAlignment(u32 pitch)
|
|||
}
|
||||
|
||||
OpenGLTexture::OpenGLTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, Type type, Format format,
|
||||
GLuint id)
|
||||
Flags flags, 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),
|
||||
static_cast<u8>(samples), type, format, flags),
|
||||
m_id(id)
|
||||
{
|
||||
}
|
||||
|
@ -126,14 +127,15 @@ bool OpenGLTexture::UseTextureStorage() const
|
|||
}
|
||||
|
||||
std::unique_ptr<OpenGLTexture> OpenGLTexture::Create(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||
Type type, Format format, const void* data, u32 data_pitch)
|
||||
Type type, Format format, Flags flags, const void* data,
|
||||
u32 data_pitch, Error* error)
|
||||
{
|
||||
if (!ValidateConfig(width, height, layers, levels, samples, type, format))
|
||||
if (!ValidateConfig(width, height, layers, levels, samples, type, format, flags, error))
|
||||
return nullptr;
|
||||
|
||||
if (layers > 1 && data)
|
||||
{
|
||||
ERROR_LOG("Loading texture array data not currently supported");
|
||||
Error::SetStringView(error, "Loading texture array data not currently supported");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -235,15 +237,16 @@ std::unique_ptr<OpenGLTexture> OpenGLTexture::Create(u32 width, u32 height, u32
|
|||
}
|
||||
}
|
||||
|
||||
GLenum error = glGetError();
|
||||
if (error != GL_NO_ERROR)
|
||||
const GLenum gl_error = glGetError();
|
||||
if (gl_error != GL_NO_ERROR)
|
||||
{
|
||||
ERROR_LOG("Failed to create texture: 0x{:X}", error);
|
||||
Error::SetStringFmt(error, "Failed to create texture: 0x{:X}", gl_error);
|
||||
glDeleteTextures(1, &id);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return std::unique_ptr<OpenGLTexture>(new OpenGLTexture(width, height, layers, levels, samples, type, format, id));
|
||||
return std::unique_ptr<OpenGLTexture>(
|
||||
new OpenGLTexture(width, height, layers, levels, samples, type, format, flags, id));
|
||||
}
|
||||
|
||||
void OpenGLTexture::CommitClear()
|
||||
|
@ -372,6 +375,16 @@ void OpenGLTexture::Unmap()
|
|||
sb->Unbind();
|
||||
}
|
||||
|
||||
void OpenGLTexture::GenerateMipmaps()
|
||||
{
|
||||
DebugAssert(HasFlag(Flags::AllowGenerateMipmaps));
|
||||
OpenGLDevice::BindUpdateTextureUnit();
|
||||
const GLenum target = GetGLTarget();
|
||||
glBindTexture(target, m_id);
|
||||
glGenerateMipmap(target);
|
||||
glBindTexture(target, 0);
|
||||
}
|
||||
|
||||
void OpenGLTexture::SetDebugName(std::string_view name)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
|
@ -405,7 +418,7 @@ void OpenGLSampler::SetDebugName(std::string_view name)
|
|||
#endif
|
||||
}
|
||||
|
||||
std::unique_ptr<GPUSampler> OpenGLDevice::CreateSampler(const GPUSampler::Config& config)
|
||||
std::unique_ptr<GPUSampler> OpenGLDevice::CreateSampler(const GPUSampler::Config& config, Error* error /* = nullptr */)
|
||||
{
|
||||
static constexpr std::array<GLenum, static_cast<u8>(GPUSampler::AddressMode::MaxCount)> ta = {{
|
||||
GL_REPEAT, // Repeat
|
||||
|
@ -433,7 +446,7 @@ std::unique_ptr<GPUSampler> OpenGLDevice::CreateSampler(const GPUSampler::Config
|
|||
glGenSamplers(1, &sampler);
|
||||
if (glGetError() != GL_NO_ERROR)
|
||||
{
|
||||
ERROR_LOG("Failed to create sampler: {:X}", sampler);
|
||||
Error::SetStringFmt(error, "Failed to create sampler: {:X}", sampler);
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -697,7 +710,7 @@ void OpenGLTextureBuffer::SetDebugName(std::string_view name)
|
|||
}
|
||||
|
||||
std::unique_ptr<GPUTextureBuffer> OpenGLDevice::CreateTextureBuffer(GPUTextureBuffer::Format format,
|
||||
u32 size_in_elements)
|
||||
u32 size_in_elements, Error* error)
|
||||
{
|
||||
const bool use_ssbo = OpenGLDevice::GetInstance().GetFeatures().texture_buffers_emulated_with_ssbo;
|
||||
const u32 buffer_size = GPUTextureBuffer::GetElementSize(format) * size_in_elements;
|
||||
|
@ -708,13 +721,13 @@ std::unique_ptr<GPUTextureBuffer> OpenGLDevice::CreateTextureBuffer(GPUTextureBu
|
|||
glGetInteger64v(GL_MAX_SHADER_STORAGE_BLOCK_SIZE, &max_ssbo_size);
|
||||
if (static_cast<GLint64>(buffer_size) > max_ssbo_size)
|
||||
{
|
||||
ERROR_LOG("Buffer size of {} not supported, max is {}", buffer_size, max_ssbo_size);
|
||||
Error::SetStringFmt(error, "Buffer size of {} not supported, max is {}", buffer_size, max_ssbo_size);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
const GLenum target = (use_ssbo ? GL_SHADER_STORAGE_BUFFER : GL_TEXTURE_BUFFER);
|
||||
std::unique_ptr<OpenGLStreamBuffer> buffer = OpenGLStreamBuffer::Create(target, buffer_size);
|
||||
std::unique_ptr<OpenGLStreamBuffer> buffer = OpenGLStreamBuffer::Create(target, buffer_size, error);
|
||||
if (!buffer)
|
||||
return {};
|
||||
buffer->Unbind();
|
||||
|
@ -726,7 +739,7 @@ std::unique_ptr<GPUTextureBuffer> OpenGLDevice::CreateTextureBuffer(GPUTextureBu
|
|||
glGenTextures(1, &texture_id);
|
||||
if (const GLenum err = glGetError(); err != GL_NO_ERROR)
|
||||
{
|
||||
ERROR_LOG("Failed to create texture for buffer: 0x{:X}", err);
|
||||
Error::SetStringFmt(error, "Failed to create texture for buffer: 0x{:X}", err);
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -772,7 +785,8 @@ OpenGLDownloadTexture::~OpenGLDownloadTexture()
|
|||
}
|
||||
|
||||
std::unique_ptr<OpenGLDownloadTexture> OpenGLDownloadTexture::Create(u32 width, u32 height, GPUTexture::Format format,
|
||||
void* memory, size_t memory_size, u32 memory_pitch)
|
||||
void* memory, size_t memory_size, u32 memory_pitch,
|
||||
Error* error)
|
||||
{
|
||||
const u32 buffer_pitch =
|
||||
memory ? memory_pitch :
|
||||
|
@ -801,7 +815,7 @@ std::unique_ptr<OpenGLDownloadTexture> OpenGLDownloadTexture::Create(u32 width,
|
|||
|
||||
if (!buffer_map)
|
||||
{
|
||||
ERROR_LOG("Failed to map persistent download buffer");
|
||||
Error::SetStringView(error, "Failed to map persistent download buffer");
|
||||
glDeleteBuffers(1, &buffer_id);
|
||||
return {};
|
||||
}
|
||||
|
@ -814,8 +828,11 @@ std::unique_ptr<OpenGLDownloadTexture> OpenGLDownloadTexture::Create(u32 width,
|
|||
const bool imported = (memory != nullptr);
|
||||
u8* cpu_buffer =
|
||||
imported ? static_cast<u8*>(memory) : static_cast<u8*>(Common::AlignedMalloc(buffer_size, VECTOR_ALIGNMENT));
|
||||
if (!cpu_buffer)
|
||||
if (!cpu_buffer) [[unlikely]]
|
||||
{
|
||||
Error::SetStringView(error, "Failed to get client-side memory pointer.");
|
||||
return {};
|
||||
}
|
||||
|
||||
return std::unique_ptr<OpenGLDownloadTexture>(
|
||||
new OpenGLDownloadTexture(width, height, format, imported, 0, cpu_buffer, buffer_size, cpu_buffer, buffer_pitch));
|
||||
|
@ -929,16 +946,17 @@ void OpenGLDownloadTexture::SetDebugName(std::string_view name)
|
|||
glObjectLabel(GL_BUFFER, m_buffer_id, static_cast<GLsizei>(name.length()), name.data());
|
||||
}
|
||||
|
||||
std::unique_ptr<GPUDownloadTexture> OpenGLDevice::CreateDownloadTexture(u32 width, u32 height,
|
||||
GPUTexture::Format format)
|
||||
std::unique_ptr<GPUDownloadTexture>
|
||||
OpenGLDevice::CreateDownloadTexture(u32 width, u32 height, GPUTexture::Format format, Error* error /* = nullptr */)
|
||||
{
|
||||
return OpenGLDownloadTexture::Create(width, height, format, nullptr, 0, 0);
|
||||
return OpenGLDownloadTexture::Create(width, height, format, nullptr, 0, 0, error);
|
||||
}
|
||||
|
||||
std::unique_ptr<GPUDownloadTexture> OpenGLDevice::CreateDownloadTexture(u32 width, u32 height,
|
||||
GPUTexture::Format format, void* memory,
|
||||
size_t memory_size, u32 memory_stride)
|
||||
size_t memory_size, u32 memory_stride,
|
||||
Error* error /* = nullptr */)
|
||||
{
|
||||
// not _really_ memory importing, but PBOs are broken on Intel....
|
||||
return OpenGLDownloadTexture::Create(width, height, format, memory, memory_size, memory_stride);
|
||||
return OpenGLDownloadTexture::Create(width, height, format, memory, memory_size, memory_stride, error);
|
||||
}
|
||||
|
|
|
@ -28,11 +28,13 @@ public:
|
|||
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;
|
||||
void Unmap() override;
|
||||
void GenerateMipmaps() override;
|
||||
|
||||
void SetDebugName(std::string_view name) override;
|
||||
|
||||
static std::unique_ptr<OpenGLTexture> Create(u32 width, u32 height, u32 layers, u32 levels, u32 samples, Type type,
|
||||
Format format, const void* data = nullptr, u32 data_pitch = 0);
|
||||
Format format, Flags flags, const void* data, u32 data_pitch,
|
||||
Error* error);
|
||||
|
||||
bool UseTextureStorage() const;
|
||||
|
||||
|
@ -46,7 +48,8 @@ public:
|
|||
OpenGLTexture& operator=(const OpenGLTexture&) = delete;
|
||||
|
||||
private:
|
||||
OpenGLTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, Type type, Format format, GLuint id);
|
||||
OpenGLTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, Type type, Format format, Flags flags,
|
||||
GLuint id);
|
||||
|
||||
GLuint m_id = 0;
|
||||
|
||||
|
@ -108,7 +111,7 @@ public:
|
|||
~OpenGLDownloadTexture() override;
|
||||
|
||||
static std::unique_ptr<OpenGLDownloadTexture> Create(u32 width, u32 height, GPUTexture::Format format, void* memory,
|
||||
size_t memory_size, u32 memory_pitch);
|
||||
size_t memory_size, u32 memory_pitch, Error* error);
|
||||
|
||||
void CopyFromTexture(u32 dst_x, u32 dst_y, GPUTexture* src, u32 src_x, u32 src_y, u32 width, u32 height,
|
||||
u32 src_layer, u32 src_level, bool use_transfer_pitch) override;
|
||||
|
|
|
@ -564,10 +564,12 @@ bool PostProcessing::Chain::CheckTargets(GPUTexture::Format target_format, u32 t
|
|||
// In case any allocs fail.
|
||||
DestroyTextures();
|
||||
|
||||
if (!(m_input_texture = g_gpu_device->FetchTexture(target_width, target_height, 1, 1, 1,
|
||||
GPUTexture::Type::RenderTarget, target_format)) ||
|
||||
!(m_output_texture = g_gpu_device->FetchTexture(target_width, target_height, 1, 1, 1,
|
||||
GPUTexture::Type::RenderTarget, target_format)))
|
||||
if (!(m_input_texture =
|
||||
g_gpu_device->FetchTexture(target_width, target_height, 1, 1, 1, GPUTexture::Type::RenderTarget,
|
||||
target_format, GPUTexture::Flags::None)) ||
|
||||
!(m_output_texture =
|
||||
g_gpu_device->FetchTexture(target_width, target_height, 1, 1, 1, GPUTexture::Type::RenderTarget,
|
||||
target_format, GPUTexture::Flags::None)))
|
||||
{
|
||||
DestroyTextures();
|
||||
return false;
|
||||
|
@ -806,7 +808,7 @@ GPUTexture* PostProcessing::GetDummyTexture()
|
|||
|
||||
const u32 zero = 0;
|
||||
s_dummy_texture = g_gpu_device->FetchTexture(1, 1, 1, 1, 1, GPUTexture::Type::Texture, GPUTexture::Format::RGBA8,
|
||||
&zero, sizeof(zero));
|
||||
GPUTexture::Flags::None, &zero, sizeof(zero));
|
||||
if (!s_dummy_texture)
|
||||
ERROR_LOG("Failed to create dummy texture.");
|
||||
|
||||
|
|
|
@ -1138,12 +1138,10 @@ bool PostProcessing::ReShadeFXShader::CreatePasses(GPUTexture::Format backbuffer
|
|||
|
||||
tex.rt_scale = 0.0f;
|
||||
tex.texture = g_gpu_device->FetchTexture(image.GetWidth(), image.GetHeight(), 1, 1, 1, GPUTexture::Type::Texture,
|
||||
GPUTexture::Format::RGBA8, image.GetPixels(), image.GetPitch());
|
||||
GPUTexture::Format::RGBA8, GPUTexture::Flags::None, image.GetPixels(),
|
||||
image.GetPitch(), error);
|
||||
if (!tex.texture)
|
||||
{
|
||||
Error::SetStringFmt(error, "Failed to create {}x{} texture ({})", image.GetWidth(), image.GetHeight(), source);
|
||||
return false;
|
||||
}
|
||||
|
||||
DEV_LOG("Loaded {}x{} texture ({})", image.GetWidth(), image.GetHeight(), source);
|
||||
}
|
||||
|
@ -1457,13 +1455,11 @@ bool PostProcessing::ReShadeFXShader::ResizeOutput(GPUTexture::Format format, u3
|
|||
|
||||
const u32 t_width = std::max(static_cast<u32>(static_cast<float>(width) * tex.rt_scale), 1u);
|
||||
const u32 t_height = std::max(static_cast<u32>(static_cast<float>(height) * tex.rt_scale), 1u);
|
||||
tex.texture = g_gpu_device->FetchTexture(t_width, t_height, 1, 1, 1, GPUTexture::Type::RenderTarget, tex.format);
|
||||
tex.texture = g_gpu_device->FetchTexture(t_width, t_height, 1, 1, 1, GPUTexture::Type::RenderTarget, tex.format,
|
||||
GPUTexture::Flags::None);
|
||||
if (!tex.texture)
|
||||
{
|
||||
ERROR_LOG("Failed to create {}x{} texture", t_width, t_height);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
m_valid = true;
|
||||
return true;
|
||||
|
|
|
@ -2012,11 +2012,8 @@ bool VulkanDevice::CreateDeviceAndMainSwapChain(std::string_view adapter, Featur
|
|||
m_main_swap_chain = std::move(swap_chain);
|
||||
}
|
||||
|
||||
if (!CreateNullTexture())
|
||||
{
|
||||
Error::SetStringView(error, "Failed to create dummy texture");
|
||||
if (!CreateNullTexture(error))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CreateBuffers() || !CreatePersistentDescriptorSets())
|
||||
{
|
||||
|
@ -2762,12 +2759,15 @@ void VulkanDevice::UnmapUniformBuffer(u32 size)
|
|||
m_dirty_flags |= DIRTY_FLAG_DYNAMIC_OFFSETS;
|
||||
}
|
||||
|
||||
bool VulkanDevice::CreateNullTexture()
|
||||
bool VulkanDevice::CreateNullTexture(Error* error)
|
||||
{
|
||||
m_null_texture = VulkanTexture::Create(1, 1, 1, 1, 1, GPUTexture::Type::RWTexture, GPUTexture::Format::RGBA8,
|
||||
VK_FORMAT_R8G8B8A8_UNORM);
|
||||
m_null_texture = VulkanTexture::Create(1, 1, 1, 1, 1, GPUTexture::Type::Texture, GPUTexture::Format::RGBA8,
|
||||
GPUTexture::Flags::AllowBindAsImage, VK_FORMAT_R8G8B8A8_UNORM, error);
|
||||
if (!m_null_texture)
|
||||
{
|
||||
Error::AddPrefix(error, "Failed to create null texture: ");
|
||||
return false;
|
||||
}
|
||||
|
||||
const VkCommandBuffer cmdbuf = GetCurrentCommandBuffer();
|
||||
const VkImageSubresourceRange srr{VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u};
|
||||
|
@ -2779,9 +2779,12 @@ bool VulkanDevice::CreateNullTexture()
|
|||
Vulkan::SetObjectName(m_device, m_null_texture->GetView(), "Null texture view");
|
||||
|
||||
// Bind null texture and point sampler state to all.
|
||||
const VkSampler point_sampler = GetSampler(GPUSampler::GetNearestConfig());
|
||||
const VkSampler point_sampler = GetSampler(GPUSampler::GetNearestConfig(), error);
|
||||
if (point_sampler == VK_NULL_HANDLE)
|
||||
{
|
||||
Error::AddPrefix(error, "Failed to get nearest sampler for init bind: ");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < MAX_TEXTURE_SAMPLERS; i++)
|
||||
m_current_samplers[i] = point_sampler;
|
||||
|
@ -3010,10 +3013,14 @@ void VulkanDevice::RenderBlankFrame(VulkanSwapChain* swap_chain)
|
|||
}
|
||||
|
||||
bool VulkanDevice::TryImportHostMemory(void* data, size_t data_size, VkBufferUsageFlags buffer_usage,
|
||||
VkDeviceMemory* out_memory, VkBuffer* out_buffer, VkDeviceSize* out_offset)
|
||||
VkDeviceMemory* out_memory, VkBuffer* out_buffer, VkDeviceSize* out_offset,
|
||||
Error* error)
|
||||
{
|
||||
if (!m_optional_extensions.vk_ext_external_memory_host)
|
||||
{
|
||||
Error::SetStringView(error, "VK_EXT_external_memory_host is not supported.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Align to the nearest page
|
||||
void* data_aligned =
|
||||
|
@ -3031,7 +3038,7 @@ bool VulkanDevice::TryImportHostMemory(void* data, size_t data_size, VkBufferUsa
|
|||
data_aligned, &pointer_properties);
|
||||
if (res != VK_SUCCESS || pointer_properties.memoryTypeBits == 0)
|
||||
{
|
||||
LOG_VULKAN_ERROR(res, "vkGetMemoryHostPointerPropertiesEXT() failed: ");
|
||||
Vulkan::SetErrorObject(error, "vkGetMemoryHostPointerPropertiesEXT() failed: ", res);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -3044,7 +3051,7 @@ bool VulkanDevice::TryImportHostMemory(void* data, size_t data_size, VkBufferUsa
|
|||
res = vmaFindMemoryTypeIndex(m_allocator, pointer_properties.memoryTypeBits, &vma_alloc_info, &memory_index);
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
LOG_VULKAN_ERROR(res, "vmaFindMemoryTypeIndex() failed: ");
|
||||
Vulkan::SetErrorObject(error, "vmaFindMemoryTypeIndex() failed: ", res);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -3060,7 +3067,7 @@ bool VulkanDevice::TryImportHostMemory(void* data, size_t data_size, VkBufferUsa
|
|||
res = vkAllocateMemory(m_device, &alloc_info, nullptr, &imported_memory);
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
LOG_VULKAN_ERROR(res, "vkAllocateMemory() failed: ");
|
||||
Vulkan::SetErrorObject(error, "vkAllocateMemory() failed: ", res);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -3080,7 +3087,7 @@ bool VulkanDevice::TryImportHostMemory(void* data, size_t data_size, VkBufferUsa
|
|||
res = vkCreateBuffer(m_device, &buffer_info, nullptr, &imported_buffer);
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
LOG_VULKAN_ERROR(res, "vkCreateBuffer() failed: ");
|
||||
Vulkan::SetErrorObject(error, "vkCreateBuffer() failed: ", res);
|
||||
if (imported_memory != VK_NULL_HANDLE)
|
||||
vkFreeMemory(m_device, imported_memory, nullptr);
|
||||
|
||||
|
@ -3125,14 +3132,13 @@ void VulkanDevice::SetRenderTargets(GPUTexture* const* rts, u32 num_rts, GPUText
|
|||
if (InRenderPass())
|
||||
EndRenderPass();
|
||||
|
||||
if (m_num_current_render_targets == 0 && !m_current_depth_target)
|
||||
{
|
||||
m_current_framebuffer = VK_NULL_HANDLE;
|
||||
if (m_num_current_render_targets == 0 && !m_current_depth_target)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_optional_extensions.vk_khr_dynamic_rendering ||
|
||||
((flags & GPUPipeline::ColorFeedbackLoop) && !m_optional_extensions.vk_khr_dynamic_rendering_local_read))
|
||||
if (!(flags & GPUPipeline::BindRenderTargetsAsImages) &&
|
||||
(!m_optional_extensions.vk_khr_dynamic_rendering ||
|
||||
((flags & GPUPipeline::ColorFeedbackLoop) && !m_optional_extensions.vk_khr_dynamic_rendering_local_read)))
|
||||
{
|
||||
m_current_framebuffer = m_framebuffer_manager.Lookup(
|
||||
(m_num_current_render_targets > 0) ? reinterpret_cast<GPUTexture**>(m_current_render_targets.data()) : nullptr,
|
||||
|
@ -3594,7 +3600,7 @@ void VulkanDevice::UnbindTexture(VulkanTexture* tex)
|
|||
}
|
||||
}
|
||||
|
||||
if (tex->IsRenderTarget() || tex->IsRWTexture())
|
||||
if (tex->IsRenderTarget())
|
||||
{
|
||||
for (u32 i = 0; i < m_num_current_render_targets; i++)
|
||||
{
|
||||
|
|
|
@ -88,15 +88,18 @@ public:
|
|||
std::optional<bool> exclusive_fullscreen_control,
|
||||
Error* error) override;
|
||||
std::unique_ptr<GPUTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||
GPUTexture::Type type, GPUTexture::Format format,
|
||||
const void* data = nullptr, u32 data_stride = 0) override;
|
||||
std::unique_ptr<GPUSampler> CreateSampler(const GPUSampler::Config& config) override;
|
||||
std::unique_ptr<GPUTextureBuffer> CreateTextureBuffer(GPUTextureBuffer::Format format, u32 size_in_elements) override;
|
||||
GPUTexture::Type type, GPUTexture::Format format, GPUTexture::Flags flags,
|
||||
const void* data = nullptr, u32 data_stride = 0,
|
||||
Error* error = nullptr) override;
|
||||
std::unique_ptr<GPUSampler> CreateSampler(const GPUSampler::Config& config, Error* error = nullptr) override;
|
||||
std::unique_ptr<GPUTextureBuffer> CreateTextureBuffer(GPUTextureBuffer::Format format, u32 size_in_elements,
|
||||
Error* error = nullptr) override;
|
||||
|
||||
std::unique_ptr<GPUDownloadTexture> CreateDownloadTexture(u32 width, u32 height, GPUTexture::Format format) override;
|
||||
std::unique_ptr<GPUDownloadTexture> CreateDownloadTexture(u32 width, u32 height, GPUTexture::Format format,
|
||||
void* memory, size_t memory_size,
|
||||
u32 memory_stride) override;
|
||||
Error* error = nullptr) override;
|
||||
std::unique_ptr<GPUDownloadTexture> CreateDownloadTexture(u32 width, u32 height, GPUTexture::Format format,
|
||||
void* memory, size_t memory_size, u32 memory_stride,
|
||||
Error* error = nullptr) override;
|
||||
|
||||
bool SupportsTextureFormat(GPUTexture::Format format) const override;
|
||||
void CopyTextureRegion(GPUTexture* dst, u32 dst_x, u32 dst_y, u32 dst_layer, u32 dst_level, GPUTexture* src,
|
||||
|
@ -351,20 +354,20 @@ private:
|
|||
void DestroyCommandBuffers();
|
||||
bool CreatePersistentDescriptorPool();
|
||||
void DestroyPersistentDescriptorPool();
|
||||
bool CreateNullTexture();
|
||||
bool CreateNullTexture(Error* error);
|
||||
bool CreateBuffers();
|
||||
void DestroyBuffers();
|
||||
bool CreatePipelineLayouts();
|
||||
void DestroyPipelineLayouts();
|
||||
bool CreatePersistentDescriptorSets();
|
||||
void DestroyPersistentDescriptorSets();
|
||||
VkSampler GetSampler(const GPUSampler::Config& config);
|
||||
VkSampler GetSampler(const GPUSampler::Config& config, Error* error = nullptr);
|
||||
void DestroySamplers();
|
||||
|
||||
void RenderBlankFrame(VulkanSwapChain* swap_chain);
|
||||
|
||||
bool TryImportHostMemory(void* data, size_t data_size, VkBufferUsageFlags buffer_usage, VkDeviceMemory* out_memory,
|
||||
VkBuffer* out_buffer, VkDeviceSize* out_offset);
|
||||
VkBuffer* out_buffer, VkDeviceSize* out_offset, Error* error);
|
||||
|
||||
/// Set dirty flags on everything to force re-bind at next draw time.
|
||||
void InvalidateCachedState();
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "common/align.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/bitutils.h"
|
||||
#include "common/error.h"
|
||||
#include "common/log.h"
|
||||
|
||||
LOG_CHANNEL(GPUDevice);
|
||||
|
@ -42,9 +43,9 @@ static VkImageLayout GetVkImageLayout(VulkanTexture::Layout layout)
|
|||
}
|
||||
|
||||
VulkanTexture::VulkanTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, Type type, Format format,
|
||||
VkImage image, VmaAllocation allocation, VkImageView view, VkFormat vk_format)
|
||||
Flags flags, VkImage image, VmaAllocation allocation, VkImageView view, VkFormat vk_format)
|
||||
: GPUTexture(static_cast<u16>(width), static_cast<u16>(height), static_cast<u8>(layers), static_cast<u8>(levels),
|
||||
static_cast<u8>(samples), type, format),
|
||||
static_cast<u8>(samples), type, format, flags),
|
||||
m_image(image), m_allocation(allocation), m_view(view), m_vk_format(vk_format)
|
||||
{
|
||||
}
|
||||
|
@ -55,9 +56,10 @@ VulkanTexture::~VulkanTexture()
|
|||
}
|
||||
|
||||
std::unique_ptr<VulkanTexture> VulkanTexture::Create(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||
Type type, Format format, VkFormat vk_format)
|
||||
Type type, Format format, Flags flags, VkFormat vk_format,
|
||||
Error* error)
|
||||
{
|
||||
if (!ValidateConfig(width, height, layers, levels, samples, type, format))
|
||||
if (!ValidateConfig(width, height, layers, levels, samples, type, format, flags, error))
|
||||
return {};
|
||||
|
||||
VulkanDevice& dev = VulkanDevice::GetInstance();
|
||||
|
@ -92,11 +94,9 @@ std::unique_ptr<VulkanTexture> VulkanTexture::Create(u32 width, u32 height, u32
|
|||
s_identity_swizzle,
|
||||
{VK_IMAGE_ASPECT_COLOR_BIT, 0, static_cast<u32>(levels), 0, 1}};
|
||||
|
||||
// TODO: Don't need the feedback loop stuff yet.
|
||||
switch (type)
|
||||
{
|
||||
case Type::Texture:
|
||||
case Type::DynamicTexture:
|
||||
{
|
||||
ici.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
}
|
||||
|
@ -120,17 +120,13 @@ std::unique_ptr<VulkanTexture> VulkanTexture::Create(u32 width, u32 height, u32
|
|||
}
|
||||
break;
|
||||
|
||||
case Type::RWTexture:
|
||||
DefaultCaseIsUnreachable();
|
||||
}
|
||||
|
||||
if ((flags & Flags::AllowBindAsImage) != Flags::None)
|
||||
{
|
||||
DebugAssert(levels == 1);
|
||||
ici.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_STORAGE_BIT |
|
||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT |
|
||||
VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return {};
|
||||
ici.usage |= VK_IMAGE_USAGE_STORAGE_BIT;
|
||||
}
|
||||
|
||||
// Use dedicated allocations for typical RT size
|
||||
|
@ -146,14 +142,9 @@ std::unique_ptr<VulkanTexture> VulkanTexture::Create(u32 width, u32 height, u32
|
|||
aci.flags &= ~VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT;
|
||||
res = vmaCreateImage(dev.GetAllocator(), &ici, &aci, &image, &allocation, nullptr);
|
||||
}
|
||||
if (res == VK_ERROR_OUT_OF_DEVICE_MEMORY)
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
ERROR_LOG("Failed to allocate device memory for {}x{} texture", width, height);
|
||||
return {};
|
||||
}
|
||||
else if (res != VK_SUCCESS)
|
||||
{
|
||||
LOG_VULKAN_ERROR(res, "vmaCreateImage failed: ");
|
||||
Vulkan::SetErrorObject(error, "vmaCreateImage failed: ", res);
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -162,13 +153,13 @@ std::unique_ptr<VulkanTexture> VulkanTexture::Create(u32 width, u32 height, u32
|
|||
res = vkCreateImageView(dev.GetVulkanDevice(), &vci, nullptr, &view);
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
LOG_VULKAN_ERROR(res, "vkCreateImageView failed: ");
|
||||
Vulkan::SetErrorObject(error, "vkCreateImageView failed: ", res);
|
||||
vmaDestroyImage(dev.GetAllocator(), image, allocation);
|
||||
return {};
|
||||
}
|
||||
|
||||
return std::unique_ptr<VulkanTexture>(
|
||||
new VulkanTexture(width, height, layers, levels, samples, type, format, image, allocation, view, vk_format));
|
||||
new VulkanTexture(width, height, layers, levels, samples, type, format, flags, image, allocation, view, vk_format));
|
||||
}
|
||||
|
||||
void VulkanTexture::Destroy(bool defer)
|
||||
|
@ -228,10 +219,9 @@ VkClearDepthStencilValue VulkanTexture::GetClearDepthValue() const
|
|||
VkCommandBuffer VulkanTexture::GetCommandBufferForUpdate()
|
||||
{
|
||||
VulkanDevice& dev = VulkanDevice::GetInstance();
|
||||
if ((m_type != Type::Texture && m_type != Type::DynamicTexture) ||
|
||||
m_use_fence_counter == dev.GetCurrentFenceCounter())
|
||||
if (m_type != Type::Texture || m_use_fence_counter == dev.GetCurrentFenceCounter())
|
||||
{
|
||||
// Console.WriteLn("Texture update within frame, can't use do beforehand");
|
||||
// DEV_LOG("Texture update within frame, can't use do beforehand");
|
||||
if (dev.InRenderPass())
|
||||
dev.EndRenderPass();
|
||||
return dev.GetCurrentCommandBuffer();
|
||||
|
@ -730,13 +720,52 @@ void VulkanTexture::MakeReadyForSampling()
|
|||
TransitionToLayout(Layout::ShaderReadOnly);
|
||||
}
|
||||
|
||||
void VulkanTexture::GenerateMipmaps()
|
||||
{
|
||||
DebugAssert(HasFlag(Flags::AllowGenerateMipmaps));
|
||||
|
||||
const VkCommandBuffer cmdbuf = GetCommandBufferForUpdate();
|
||||
|
||||
if (m_layout == Layout::Undefined)
|
||||
TransitionToLayout(cmdbuf, Layout::TransferSrc);
|
||||
|
||||
for (u32 layer = 0; layer < m_layers; layer++)
|
||||
{
|
||||
for (u32 dst_level = 1; dst_level < m_levels; dst_level++)
|
||||
{
|
||||
const u32 src_level = dst_level - 1;
|
||||
const u32 src_width = std::max<u32>(m_width >> src_level, 1u);
|
||||
const u32 src_height = std::max<u32>(m_height >> src_level, 1u);
|
||||
const u32 dst_width = std::max<u32>(m_width >> dst_level, 1u);
|
||||
const u32 dst_height = std::max<u32>(m_height >> dst_level, 1u);
|
||||
|
||||
TransitionSubresourcesToLayout(cmdbuf, layer, 1, src_level, 1, m_layout, Layout::TransferSrc);
|
||||
TransitionSubresourcesToLayout(cmdbuf, layer, 1, dst_level, 1, m_layout, Layout::TransferDst);
|
||||
|
||||
const VkImageBlit blit = {
|
||||
{VK_IMAGE_ASPECT_COLOR_BIT, src_level, 0u, 1u}, // srcSubresource
|
||||
{{0, 0, 0}, {static_cast<s32>(src_width), static_cast<s32>(src_height), 1}}, // srcOffsets
|
||||
{VK_IMAGE_ASPECT_COLOR_BIT, dst_level, 0u, 1u}, // dstSubresource
|
||||
{{0, 0, 0}, {static_cast<s32>(dst_width), static_cast<s32>(dst_height), 1}} // dstOffsets
|
||||
};
|
||||
|
||||
vkCmdBlitImage(cmdbuf, m_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_image,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, VK_FILTER_LINEAR);
|
||||
|
||||
TransitionSubresourcesToLayout(cmdbuf, layer, 1, src_level, 1, Layout::TransferSrc, m_layout);
|
||||
TransitionSubresourcesToLayout(cmdbuf, layer, 1, dst_level, 1, Layout::TransferDst, m_layout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<GPUTexture> VulkanDevice::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||
GPUTexture::Type type, GPUTexture::Format format,
|
||||
const void* data /* = nullptr */, u32 data_stride /* = 0 */)
|
||||
GPUTexture::Flags flags, const void* data /* = nullptr */,
|
||||
u32 data_stride /* = 0 */, Error* error /* = nullptr */)
|
||||
{
|
||||
const VkFormat vk_format = VulkanDevice::TEXTURE_FORMAT_MAPPING[static_cast<u8>(format)];
|
||||
std::unique_ptr<VulkanTexture> tex =
|
||||
VulkanTexture::Create(width, height, layers, levels, samples, type, format, vk_format);
|
||||
VulkanTexture::Create(width, height, layers, levels, samples, type, format, flags, vk_format, error);
|
||||
if (tex && data)
|
||||
tex->Update(0, 0, width, height, data, data_stride);
|
||||
|
||||
|
@ -757,7 +786,7 @@ void VulkanSampler::SetDebugName(std::string_view name)
|
|||
Vulkan::SetObjectName(VulkanDevice::GetInstance().GetVulkanDevice(), m_sampler, name);
|
||||
}
|
||||
|
||||
VkSampler VulkanDevice::GetSampler(const GPUSampler::Config& config)
|
||||
VkSampler VulkanDevice::GetSampler(const GPUSampler::Config& config, Error* error)
|
||||
{
|
||||
const auto it = m_sampler_map.find(config.key);
|
||||
if (it != m_sampler_map.end())
|
||||
|
@ -833,7 +862,10 @@ VkSampler VulkanDevice::GetSampler(const GPUSampler::Config& config)
|
|||
VkSampler sampler = VK_NULL_HANDLE;
|
||||
VkResult res = vkCreateSampler(m_device, &ci, nullptr, &sampler);
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
LOG_VULKAN_ERROR(res, "vkCreateSampler() failed: ");
|
||||
Vulkan::SetErrorObject(error, "vkCreateSampler() failed: ", res);
|
||||
}
|
||||
|
||||
m_sampler_map.emplace(config.key, sampler);
|
||||
return sampler;
|
||||
|
@ -849,9 +881,9 @@ void VulkanDevice::DestroySamplers()
|
|||
m_sampler_map.clear();
|
||||
}
|
||||
|
||||
std::unique_ptr<GPUSampler> VulkanDevice::CreateSampler(const GPUSampler::Config& config)
|
||||
std::unique_ptr<GPUSampler> VulkanDevice::CreateSampler(const GPUSampler::Config& config, Error* error /* = nullptr */)
|
||||
{
|
||||
const VkSampler vsampler = GetSampler(config);
|
||||
const VkSampler vsampler = GetSampler(config, error);
|
||||
if (vsampler == VK_NULL_HANDLE)
|
||||
return {};
|
||||
|
||||
|
@ -925,7 +957,7 @@ void VulkanTextureBuffer::SetDebugName(std::string_view name)
|
|||
}
|
||||
|
||||
std::unique_ptr<GPUTextureBuffer> VulkanDevice::CreateTextureBuffer(GPUTextureBuffer::Format format,
|
||||
u32 size_in_elements)
|
||||
u32 size_in_elements, Error* error)
|
||||
{
|
||||
static constexpr std::array<VkFormat, static_cast<u8>(GPUTextureBuffer::Format::MaxCount)> format_mapping = {{
|
||||
VK_FORMAT_R16_UINT, // R16UI
|
||||
|
@ -939,7 +971,7 @@ std::unique_ptr<GPUTextureBuffer> VulkanDevice::CreateTextureBuffer(GPUTextureBu
|
|||
tb->m_descriptor_set = AllocatePersistentDescriptorSet(m_single_texture_buffer_ds_layout);
|
||||
if (tb->m_descriptor_set == VK_NULL_HANDLE)
|
||||
{
|
||||
ERROR_LOG("Failed to allocate persistent descriptor set for texture buffer.");
|
||||
Error::SetStringView(error, "Failed to allocate persistent descriptor set for texture buffer.");
|
||||
tb->Destroy(false);
|
||||
return {};
|
||||
}
|
||||
|
@ -996,7 +1028,7 @@ VulkanDownloadTexture::~VulkanDownloadTexture()
|
|||
|
||||
std::unique_ptr<VulkanDownloadTexture> VulkanDownloadTexture::Create(u32 width, u32 height, GPUTexture::Format format,
|
||||
void* memory, size_t memory_size,
|
||||
u32 memory_stride)
|
||||
u32 memory_stride, Error* error)
|
||||
{
|
||||
VulkanDevice& dev = VulkanDevice::GetInstance();
|
||||
VmaAllocation allocation = VK_NULL_HANDLE;
|
||||
|
@ -1031,7 +1063,7 @@ std::unique_ptr<VulkanDownloadTexture> VulkanDownloadTexture::Create(u32 width,
|
|||
VkResult res = vmaCreateBuffer(VulkanDevice::GetInstance().GetAllocator(), &bci, &aci, &buffer, &allocation, &ai);
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
LOG_VULKAN_ERROR(res, "vmaCreateBuffer() failed: ");
|
||||
Vulkan::SetErrorObject(error, "vmaCreateBuffer() failed: ", res);
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -1045,7 +1077,7 @@ std::unique_ptr<VulkanDownloadTexture> VulkanDownloadTexture::Create(u32 width,
|
|||
Assert(buffer_size <= memory_size);
|
||||
|
||||
if (!dev.TryImportHostMemory(memory, memory_size, VK_BUFFER_USAGE_TRANSFER_DST_BIT, &dev_memory, &buffer,
|
||||
&memory_offset))
|
||||
&memory_offset, error))
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
@ -1177,15 +1209,16 @@ void VulkanDownloadTexture::SetDebugName(std::string_view name)
|
|||
Vulkan::SetObjectName(VulkanDevice::GetInstance().GetVulkanDevice(), m_buffer, name);
|
||||
}
|
||||
|
||||
std::unique_ptr<GPUDownloadTexture> VulkanDevice::CreateDownloadTexture(u32 width, u32 height,
|
||||
GPUTexture::Format format)
|
||||
std::unique_ptr<GPUDownloadTexture>
|
||||
VulkanDevice::CreateDownloadTexture(u32 width, u32 height, GPUTexture::Format format, Error* error /* = nullptr */)
|
||||
{
|
||||
return VulkanDownloadTexture::Create(width, height, format, nullptr, 0, 0);
|
||||
return VulkanDownloadTexture::Create(width, height, format, nullptr, 0, 0, error);
|
||||
}
|
||||
|
||||
std::unique_ptr<GPUDownloadTexture> VulkanDevice::CreateDownloadTexture(u32 width, u32 height,
|
||||
GPUTexture::Format format, void* memory,
|
||||
size_t memory_size, u32 memory_stride)
|
||||
size_t memory_size, u32 memory_stride,
|
||||
Error* error /* = nullptr */)
|
||||
{
|
||||
return VulkanDownloadTexture::Create(width, height, format, memory, memory_size, memory_stride);
|
||||
return VulkanDownloadTexture::Create(width, height, format, memory, memory_size, memory_stride, error);
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ public:
|
|||
~VulkanTexture() override;
|
||||
|
||||
static std::unique_ptr<VulkanTexture> Create(u32 width, u32 height, u32 layers, u32 levels, u32 samples, Type type,
|
||||
Format format, VkFormat vk_format);
|
||||
Format format, Flags flags, VkFormat vk_format, Error* error);
|
||||
void Destroy(bool defer);
|
||||
|
||||
ALWAYS_INLINE VkImage GetImage() const { return m_image; }
|
||||
|
@ -54,6 +54,7 @@ public:
|
|||
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 MakeReadyForSampling() override;
|
||||
void GenerateMipmaps() override;
|
||||
|
||||
void SetDebugName(std::string_view name) override;
|
||||
|
||||
|
@ -80,8 +81,8 @@ public:
|
|||
VkDescriptorSet GetDescriptorSetWithSampler(VkSampler sampler);
|
||||
|
||||
private:
|
||||
VulkanTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, Type type, Format format, VkImage image,
|
||||
VmaAllocation allocation, VkImageView view, VkFormat vk_format);
|
||||
VulkanTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, Type type, Format format, Flags flags,
|
||||
VkImage image, VmaAllocation allocation, VkImageView view, VkFormat vk_format);
|
||||
|
||||
VkCommandBuffer GetCommandBufferForUpdate();
|
||||
void CopyTextureDataForUpload(void* dst, const void* src, u32 width, u32 height, u32 pitch, u32 upload_pitch) const;
|
||||
|
@ -159,7 +160,7 @@ public:
|
|||
~VulkanDownloadTexture() override;
|
||||
|
||||
static std::unique_ptr<VulkanDownloadTexture> Create(u32 width, u32 height, GPUTexture::Format format, void* memory,
|
||||
size_t memory_size, u32 memory_stride);
|
||||
size_t memory_size, u32 memory_stride, Error* error);
|
||||
|
||||
void CopyFromTexture(u32 dst_x, u32 dst_y, GPUTexture* src, u32 src_x, u32 src_y, u32 width, u32 height,
|
||||
u32 src_layer, u32 src_level, bool use_transfer_pitch) override;
|
||||
|
|
Loading…
Reference in New Issue