From 3ff1b04576dad862148313d51aadd1a409f3272e Mon Sep 17 00:00:00 2001 From: Stenzek Date: Thu, 21 Nov 2024 00:56:07 +1000 Subject: [PATCH] GPUDevice: Support generating mipmaps --- src/common/log_channels.h | 1 - src/core/gpu.cpp | 16 +- src/core/gpu_hw.cpp | 104 ++++++------ src/core/gpu_hw.h | 2 +- src/core/gpu_hw_texture_cache.cpp | 16 +- src/core/gpu_sw.cpp | 4 +- src/core/imgui_overlays.cpp | 6 +- src/util/d3d11_device.cpp | 19 +-- src/util/d3d11_device.h | 19 ++- src/util/d3d11_stream_buffer.cpp | 5 +- src/util/d3d11_stream_buffer.h | 4 +- src/util/d3d11_texture.cpp | 117 +++++++------ src/util/d3d11_texture.h | 11 +- src/util/d3d12_builders.cpp | 22 --- src/util/d3d12_builders.h | 7 - src/util/d3d12_descriptor_heap_manager.cpp | 1 - src/util/d3d12_device.cpp | 187 ++++++++++++++++++++- src/util/d3d12_device.h | 36 ++-- src/util/d3d12_texture.cpp | 160 ++++++++++-------- src/util/d3d12_texture.h | 7 +- src/util/gpu_device.cpp | 48 ++++-- src/util/gpu_device.h | 29 ++-- src/util/gpu_framebuffer_manager.h | 2 +- src/util/gpu_texture.cpp | 60 +++++-- src/util/gpu_texture.h | 47 ++++-- src/util/imgui_fullscreen.cpp | 8 +- src/util/imgui_manager.cpp | 12 +- src/util/media_capture.cpp | 2 +- src/util/metal_device.h | 28 +-- src/util/metal_device.mm | 85 ++++++---- src/util/metal_stream_buffer.h | 4 +- src/util/metal_stream_buffer.mm | 5 +- src/util/opengl_device.cpp | 5 +- src/util/opengl_device.h | 17 +- src/util/opengl_stream_buffer.cpp | 33 ++-- src/util/opengl_stream_buffer.h | 4 +- src/util/opengl_texture.cpp | 64 ++++--- src/util/opengl_texture.h | 9 +- src/util/postprocessing.cpp | 12 +- src/util/postprocessing_shader_fx.cpp | 12 +- src/util/vulkan_device.cpp | 44 ++--- src/util/vulkan_device.h | 23 +-- src/util/vulkan_texture.cpp | 119 ++++++++----- src/util/vulkan_texture.h | 9 +- 44 files changed, 898 insertions(+), 527 deletions(-) diff --git a/src/common/log_channels.h b/src/common/log_channels.h index 305f06490..b075a8764 100644 --- a/src/common/log_channels.h +++ b/src/common/log_channels.h @@ -31,7 +31,6 @@ X(GPUDevice) \ X(GPUDump) \ X(GPUShaderCache) \ - X(GPUTexture) \ X(GPUTextureCache) \ X(GPU_HW) \ X(GPU_SW) \ diff --git a/src/core/gpu.cpp b/src/core/gpu.cpp index 9ec22af4a..22946bd1b 100644 --- a/src/core/gpu.cpp +++ b/src/core/gpu.cpp @@ -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; diff --git a/src/core/gpu_hw.cpp b/src/core/gpu_hw.cpp index 3b93b2f3d..4e4d6bf9e 100644 --- a/src/core/gpu_hw.cpp +++ b/src/core/gpu_hw.cpp @@ -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(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 level_texture = g_gpu_device->FetchAutoRecycleTexture( - width, height, 1, m_downsample_scale_or_levels, 1, GPUTexture::Type::Texture, VRAM_RT_FORMAT); - std::unique_ptr 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 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 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) { diff --git a/src/core/gpu_hw.h b/src/core/gpu_hw.h index 46bdc78fa..53fb6da01 100644 --- a/src/core/gpu_hw.h +++ b/src/core/gpu_hw.h @@ -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(); diff --git a/src/core/gpu_hw_texture_cache.cpp b/src/core/gpu_hw_texture_cache.cpp index f7f825887..0f6ecc124 100644 --- a/src/core/gpu_hw_texture_cache.cpp +++ b/src/core/gpu_hw_texture_cache.cpp @@ -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 replacement_tex = - g_gpu_device->FetchTexture(new_width, new_height, 1, 1, 1, GPUTexture::Type::Texture, REPLACEMENT_TEXTURE_FORMAT); + std::unique_ptr 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; diff --git a/src/core/gpu_sw.cpp b/src/core/gpu_sw.cpp index 068db4164..a29d99860 100644 --- a/src/core/gpu_sw.cpp +++ b/src/core/gpu_sw.cpp @@ -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(format)); } diff --git a/src/core/imgui_overlays.cpp b/src/core/imgui_overlays.cpp index 3c8239506..e21f1cf94 100644 --- a/src/core/imgui_overlays.cpp +++ b/src/core/imgui_overlays.cpp @@ -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"); } diff --git a/src/util/d3d11_device.cpp b/src/util/d3d11_device.cpp index c6d44392c..c04a1e417 100644 --- a/src/util/d3d11_device.cpp +++ b/src/util/d3d11_device.cpp @@ -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(texture))) || !(texture->IsDepthStencil() && (!m_current_depth_target || m_current_depth_target != static_cast(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++) { diff --git a/src/util/d3d11_device.h b/src/util/d3d11_device.h index e1b327250..d06a75872 100644 --- a/src/util/d3d11_device.h +++ b/src/util/d3d11_device.h @@ -50,15 +50,18 @@ public: std::optional exclusive_fullscreen_control, Error* error) override; std::unique_ptr 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 CreateSampler(const GPUSampler::Config& config) override; - std::unique_ptr 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 CreateSampler(const GPUSampler::Config& config, Error* error = nullptr) override; + std::unique_ptr CreateTextureBuffer(GPUTextureBuffer::Format format, u32 size_in_elements, + Error* error = nullptr) override; - std::unique_ptr CreateDownloadTexture(u32 width, u32 height, GPUTexture::Format format) override; std::unique_ptr 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 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(); diff --git a/src/util/d3d11_stream_buffer.cpp b/src/util/d3d11_stream_buffer.cpp index 8a0179e36..adb59f180 100644 --- a/src/util/d3d11_stream_buffer.cpp +++ b/src/util/d3d11_stream_buffer.cpp @@ -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; } diff --git a/src/util/d3d11_stream_buffer.h b/src/util/d3d11_stream_buffer.h index c09a08d40..5c9aced3c 100644 --- a/src/util/d3d11_stream_buffer.h +++ b/src/util/d3d11_stream_buffer.h @@ -9,6 +9,8 @@ #include #include +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 diff --git a/src/util/d3d11_texture.cpp b/src/util/d3d11_texture.cpp index 9615d95cb..78b441069 100644 --- a/src/util/d3d11_texture.cpp +++ b/src/util/d3d11_texture.cpp @@ -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 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 D3D11Device::CreateSampler(const GPUSampler::Config& config) +std::unique_ptr D3D11Device::CreateSampler(const GPUSampler::Config& config, Error* error) { static constexpr std::array(GPUSampler::AddressMode::MaxCount)> ta = {{ D3D11_TEXTURE_ADDRESS_WRAP, // Repeat @@ -87,7 +90,7 @@ std::unique_ptr 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(hr)); + Error::SetHResult(error, "CreateSamplerState() failed: ", hr); return {}; } @@ -95,10 +98,10 @@ std::unique_ptr D3D11Device::CreateSampler(const GPUSampler::Config& } D3D11Texture::D3D11Texture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, Type type, Format format, - ComPtr texture, ComPtr srv, + Flags flags, ComPtr texture, ComPtr srv, ComPtr rtv_dsv, ComPtr uav) : GPUTexture(static_cast(width), static_cast(height), static_cast(layers), static_cast(levels), - static_cast(samples), type, format), + static_cast(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::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; - usage = D3D11_USAGE_DYNAMIC; - cpu_access = D3D11_CPU_ACCESS_WRITE; + + case Type::RenderTarget: + bind_flags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE; break; - case Type::RWTexture: - bind_flags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE; - break; - default: + + 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; } 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::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(tex_hr), width, height, levels, samples, static_cast(format), bind_flags, - initial_data); + Error::SetHResult(error, "CreateTexture2D() failed: ", tex_hr); return nullptr; } @@ -288,7 +309,7 @@ std::unique_ptr 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(hr)); + Error::SetHResult(error, "CreateShaderResourceView() failed: ", hr); return nullptr; } } @@ -303,7 +324,7 @@ std::unique_ptr 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(hr)); + Error::SetHResult(error, "CreateRenderTargetView() failed: ", hr); return nullptr; } @@ -318,7 +339,7 @@ std::unique_ptr 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(hr)); + Error::SetHResult(error, "CreateDepthStencilView() failed: ", hr); return nullptr; } @@ -334,12 +355,12 @@ std::unique_ptr 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(hr)); + Error::SetHResult(error, "CreateUnorderedAccessView() failed: ", hr); return nullptr; } } - return std::unique_ptr(new D3D11Texture(width, height, layers, levels, samples, type, format, + return std::unique_ptr(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(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(hr)); + Error::SetHResult(error, "CreateShaderResourceView() failed: ", hr); return false; } @@ -395,10 +416,10 @@ void D3D11TextureBuffer::SetDebugName(std::string_view name) } std::unique_ptr D3D11Device::CreateTextureBuffer(GPUTextureBuffer::Format format, - u32 size_in_elements) + u32 size_in_elements, Error* error /* = nullptr */) { std::unique_ptr tb = std::make_unique(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::Create(u32 width, u32 height, GPUTexture::Format format) +std::unique_ptr 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::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 D3D11Device::CreateDownloadTexture(u32 width, u32 height, GPUTexture::Format format) +std::unique_ptr 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 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 {}; } diff --git a/src/util/d3d11_texture.h b/src/util/d3d11_texture.h index 03840a070..25f636442 100644 --- a/src/util/d3d11_texture.h +++ b/src/util/d3d11_texture.h @@ -77,8 +77,8 @@ public: ALWAYS_INLINE operator bool() const { return static_cast(m_texture); } static std::unique_ptr 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 texture, ComPtr srv, ComPtr rtv_dsv, ComPtr 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 Create(u32 width, u32 height, GPUTexture::Format format); + static std::unique_ptr 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; diff --git a/src/util/d3d12_builders.cpp b/src/util/d3d12_builders.cpp index ed297cc9e..230641c3f 100644 --- a/src/util/d3d12_builders.cpp +++ b/src/util/d3d12_builders.cpp @@ -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; diff --git a/src/util/d3d12_builders.h b/src/util/d3d12_builders.h index 9dbffcf77..bf5e3531f 100644 --- a/src/util/d3d12_builders.h +++ b/src/util/d3d12_builders.h @@ -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(); diff --git a/src/util/d3d12_descriptor_heap_manager.cpp b/src/util/d3d12_descriptor_heap_manager.cpp index 7da9d7101..6ea24ece5 100644 --- a/src/util/d3d12_descriptor_heap_manager.cpp +++ b/src/util/d3d12_descriptor_heap_manager.cpp @@ -83,7 +83,6 @@ bool D3D12DescriptorHeapManager::Allocate(D3D12DescriptorHandle* handle) return true; } - Panic("Out of fixed descriptors"); return false; } diff --git a/src/util/d3d12_device.cpp b/src/util/d3d12_device.cpp index be58487c9..964d067cc 100644 --- a/src/util/d3d12_device.cpp +++ b/src/util/d3d12_device.cpp @@ -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 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(GPUPipeline::Layout::SingleTextureAndPushConstants)].Get(); + ComPtr& pipeline = m_mipmap_render_pipelines[static_cast(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(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(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(dst_width), static_cast(dst_height), 0.0f, 1.0f}; + cmdlist->RSSetViewports(1, &vp); + + const D3D12_RECT scissor = {0, 0, static_cast(dst_width), static_cast(dst_height)}; + cmdlist->RSSetScissorRects(1, &scissor); + + cmdlist->SetPipelineState(pipeline.Get()); + cmdlist->SetGraphicsRootDescriptorTable(0, srv_handle); + cmdlist->SetGraphicsRootDescriptorTable(1, static_cast(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)) diff --git a/src/util/d3d12_device.h b/src/util/d3d12_device.h index ba065cfc5..6306a1376 100644 --- a/src/util/d3d12_device.h +++ b/src/util/d3d12_device.h @@ -71,15 +71,18 @@ public: std::optional exclusive_fullscreen_control, Error* error) override; std::unique_ptr 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 CreateSampler(const GPUSampler::Config& config) override; - std::unique_ptr 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 CreateSampler(const GPUSampler::Config& config, Error* error = nullptr) override; + std::unique_ptr CreateTextureBuffer(GPUTextureBuffer::Format format, u32 size_in_elements, + Error* error = nullptr) override; - std::unique_ptr CreateDownloadTexture(u32 width, u32 height, GPUTexture::Format format) override; std::unique_ptr 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 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, static_cast(GPUTexture::Format::MaxCount)> m_mipmap_render_pipelines = + {}; }; class D3D12SwapChain : public GPUSwapChain diff --git a/src/util/d3d12_texture.cpp b/src/util/d3d12_texture.cpp index 789761935..4305f7afd 100644 --- a/src/util/d3d12_texture.cpp +++ b/src/util/d3d12_texture.cpp @@ -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 resource, + Flags flags, DXGI_FORMAT dxgi_format, ComPtr resource, ComPtr allocation, const D3D12DescriptorHandle& srv_descriptor, const D3D12DescriptorHandle& write_descriptor, const D3D12DescriptorHandle& uav_descriptor, WriteDescriptorType wdtype, D3D12_RESOURCE_STATES resource_state) : GPUTexture(static_cast(width), static_cast(height), static_cast(layers), static_cast(levels), - static_cast(samples), type, format), + static_cast(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 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 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 D3D12Device::CreateTexture(u32 width, u32 height, u3 } break; - case GPUTexture::Type::RWTexture: - { - 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; - } - break; + DefaultCaseIsUnreachable(); + } - default: - return {}; + if ((flags & GPUTexture::Flags::AllowBindAsImage) != GPUTexture::Flags::None) + { + DebugAssert(levels == 1); + allocationDesc.Flags |= D3D12MA::ALLOCATION_FLAG_COMMITTED; + desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; + } + + 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 resource; @@ -115,10 +117,7 @@ std::unique_ptr 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(hr)); - + Error::SetHResult(error, "CreateResource() failed: ", hr); return {}; } @@ -126,16 +125,19 @@ std::unique_ptr 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 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 D3D12Device::CreateTexture(u32 width, u32 height, u3 } break; - case GPUTexture::Type::RWTexture: + DefaultCaseIsUnreachable(); + } + + if ((flags & GPUTexture::Flags::AllowBindAsImage) != GPUTexture::Flags::None) + { + if (!CreateUAVDescriptor(resource.Get(), samples, fm.srv_format, &uav_descriptor, error)) { - write_descriptor_type = D3D12Texture::WriteDescriptorType::RTV; - if (!CreateRTVDescriptor(resource.Get(), samples, fm.rtv_format, &write_descriptor)) - { - m_descriptor_heap_manager.Free(&srv_descriptor); - return {}; - } - - if (!CreateUAVDescriptor(resource.Get(), samples, fm.srv_format, &uav_descriptor)) - { + 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; + m_descriptor_heap_manager.Free(&srv_descriptor); + return {}; + } } std::unique_ptr 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 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(m_width >> src_level, 1u); + const u32 src_height = std::max(m_height >> src_level, 1u); + const u32 dst_width = std::max(m_width >> dst_level, 1u); + const u32 dst_height = std::max(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 D3D12Device::CreateSampler(const GPUSampler::Config& config) +std::unique_ptr 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(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(m_format)], D3D12_SRV_DIMENSION_BUFFER, @@ -831,11 +849,11 @@ void D3D12TextureBuffer::SetDebugName(std::string_view name) } std::unique_ptr D3D12Device::CreateTextureBuffer(GPUTextureBuffer::Format format, - u32 size_in_elements) + u32 size_in_elements, Error* error /* = nullptr */) { std::unique_ptr tb = std::make_unique(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::Create(u32 width, u32 height, GPUTexture::Format format) +std::unique_ptr 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::Create(u32 width, u3 ComPtr allocation; ComPtr 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 D3D12Device::CreateDownloadTexture(u32 width, u32 height, GPUTexture::Format format) +std::unique_ptr 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 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 {}; } diff --git a/src/util/d3d12_texture.h b/src/util/d3d12_texture.h index c8f31a022..051d1ca0d 100644 --- a/src/util/d3d12_texture.h +++ b/src/util/d3d12_texture.h @@ -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 resource, ComPtr 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 Create(u32 width, u32 height, GPUTexture::Format format); + static std::unique_ptr 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; diff --git a/src/util/gpu_device.cpp b/src/util/gpu_device.cpp index 6a4c3a6dd..3c6c2fb25 100644 --- a/src/util/gpu_device.cpp +++ b/src/util/gpu_device.cpp @@ -590,10 +590,10 @@ bool GPUDevice::GetPipelineCacheData(DynamicHeapArray* 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 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 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 ret; @@ -966,7 +972,7 @@ std::unique_ptr GPUDevice::FetchTexture(u32 width, u32 height, u32 l static_cast(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 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 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 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(ret.release()); } @@ -1044,7 +1062,7 @@ void GPUDevice::RecycleTexture(std::unique_ptr texture) static_cast(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* 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 new_tex = FetchTexture(new_width, new_height, 1, 1, 1, type, format); + std::unique_ptr 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); diff --git a/src/util/gpu_device.h b/src/util/gpu_device.h index 6c1060c60..04efc1fc6 100644 --- a/src/util/gpu_device.h +++ b/src/util/gpu_device.h @@ -693,27 +693,28 @@ public: virtual std::unique_ptr 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 CreateSampler(const GPUSampler::Config& config) = 0; - virtual std::unique_ptr 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 CreateSampler(const GPUSampler::Config& config, Error* error = nullptr) = 0; + virtual std::unique_ptr CreateTextureBuffer(GPUTextureBuffer::Format format, u32 size_in_elements, + Error* error = nullptr) = 0; // Texture pooling. std::unique_ptr 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 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 texture); void PurgeTexturePool(); - virtual std::unique_ptr CreateDownloadTexture(u32 width, u32 height, - GPUTexture::Format format) = 0; virtual std::unique_ptr 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 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* 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 { diff --git a/src/util/gpu_framebuffer_manager.h b/src/util/gpu_framebuffer_manager.h index e5e24c7e9..072cdd701 100644 --- a/src/util/gpu_framebuffer_manager.h +++ b/src/util/gpu_framebuffer_manager.h @@ -92,7 +92,7 @@ template void GPUFramebufferManager::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)) diff --git a/src/util/gpu_texture.cpp b/src/util/gpu_texture.cpp index aff26f256..c1bad139b 100644 --- a/src/util/gpu_texture.cpp +++ b/src/util/gpu_texture.cpp @@ -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(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 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(format)); return false; } } diff --git a/src/util/gpu_texture.h b/src/util/gpu_texture.h index 0528090f6..5139c74b5 100644 --- a/src/util/gpu_texture.h +++ b/src/util/gpu_texture.h @@ -11,6 +11,8 @@ #include #include +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& 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(m_flags) & static_cast(flag)) != 0); } ALWAYS_INLINE GSVector4i GetRect() const { return GSVector4i(0, 0, static_cast(m_width), static_cast(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: diff --git a/src/util/imgui_fullscreen.cpp b/src/util/imgui_fullscreen.cpp index 1a5da2f86..b7a6b41ce 100644 --- a/src/util/imgui_fullscreen.cpp +++ b/src/util/imgui_fullscreen.cpp @@ -290,9 +290,9 @@ const std::shared_ptr& ImGuiFullscreen::GetPlaceholderTexture() std::unique_ptr ImGuiFullscreen::CreateTextureFromImage(const RGBA8Image& image) { - std::unique_ptr 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 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 ImGuiFullscreen::UploadTexture(std::string_view path { std::unique_ptr 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()); diff --git a/src/util/imgui_manager.cpp b/src/util/imgui_manager.cpp index f1153d413..3e6a6cfd6 100644 --- a/src/util/imgui_manager.cpp +++ b/src/util/imgui_manager.cpp @@ -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; } diff --git a/src/util/media_capture.cpp b/src/util/media_capture.cpp index c757f3c37..01541401e 100644 --- a/src/util/media_capture.cpp +++ b/src/util/media_capture.cpp @@ -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); diff --git a/src/util/metal_device.h b/src/util/metal_device.h index b1a502755..b83880418 100644 --- a/src/util/metal_device.h +++ b/src/util/metal_device.h @@ -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 texture, u16 width, u16 height, u8 layers, u8 levels, u8 samples, Type type, - Format format); + Format format, Flags flags); id m_texture; @@ -150,7 +151,7 @@ public: ~MetalDownloadTexture() override; static std::unique_ptr 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 GetMTLBuffer() const { return m_buffer.GetBuffer(); } - bool CreateBuffer(id device); + bool CreateBuffer(id device, Error* error); // Inherited via GPUTextureBuffer void* Map(u32 required_elements) override; @@ -234,15 +235,18 @@ public: std::optional exclusive_fullscreen_control, Error* error) override; std::unique_ptr 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 CreateSampler(const GPUSampler::Config& config) override; - std::unique_ptr 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 CreateSampler(const GPUSampler::Config& config, Error* error = nullptr) override; + std::unique_ptr CreateTextureBuffer(GPUTextureBuffer::Format format, u32 size_in_elements, + Error* error = nullptr) override; - std::unique_ptr CreateDownloadTexture(u32 width, u32 height, GPUTexture::Format format) override; std::unique_ptr 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 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>; @@ -377,7 +381,7 @@ private: void RenderBlankFrame(MetalSwapChain* swap_chain); - bool CreateBuffers(); + bool CreateBuffers(Error* error); void DestroyBuffers(); bool IsRenderTargetBound(const GPUTexture* tex) const; diff --git a/src/util/metal_device.mm b/src/util/metal_device.mm index ba3cd045b..251f49904 100644 --- a/src/util/metal_device.mm +++ b/src/util/metal_device.mm @@ -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 MetalDevice::CreatePipeline(const GPUPipeline::Comp } MetalTexture::MetalTexture(id 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 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 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(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 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 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 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 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::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::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::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 MetalDevice::CreateDownloadTexture(u32 width, u32 height, GPUTexture::Format format) +std::unique_ptr 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 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 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 MetalDevice::CreateSampler(const GPUSampler::Config& config) +std::unique_ptr MetalDevice::CreateSampler(const GPUSampler::Config& config, Error* error) { @autoreleasepool { @@ -1448,7 +1460,7 @@ std::unique_ptr 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 MetalDevice::CreateSampler(const GPUSampler::Config& id 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 device) +bool MetalTextureBuffer::CreateBuffer(id 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 MetalDevice::CreateTextureBuffer(GPUTextureBuffer::Format format, - u32 size_in_elements) + u32 size_in_elements, Error* error) { std::unique_ptr tb = std::make_unique(format, size_in_elements); - if (!tb->CreateBuffer(m_device)) + if (!tb->CreateBuffer(m_device, error)) tb.reset(); return tb; diff --git a/src/util/metal_stream_buffer.h b/src/util/metal_stream_buffer.h index 6db4da91c..1399c7d42 100644 --- a/src/util/metal_stream_buffer.h +++ b/src/util/metal_stream_buffer.h @@ -19,6 +19,8 @@ #include #include +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 device, u32 size); + bool Create(id device, u32 size, Error* error); void Destroy(); bool ReserveMemory(u32 num_bytes, u32 alignment); diff --git a/src/util/metal_stream_buffer.mm b/src/util/metal_stream_buffer.mm index 1bb958638..66a072f7d 100644 --- a/src/util/metal_stream_buffer.mm +++ b/src/util/metal_stream_buffer.mm @@ -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 device, u32 size) +bool MetalStreamBuffer::Create(id device, u32 size, Error* error) { @autoreleasepool { @@ -27,7 +28,7 @@ bool MetalStreamBuffer::Create(id device, u32 size) id new_buffer = [device newBufferWithLength:size options:options]; if (new_buffer == nil) { - ERROR_LOG("Failed to create buffer."); + Error::SetStringView(error, "newBufferWithLength failed"); return false; } diff --git a/src/util/opengl_device.cpp b/src/util/opengl_device.cpp index 29a43df2e..97d169b15 100644 --- a/src/util/opengl_device.cpp +++ b/src/util/opengl_device.cpp @@ -60,9 +60,10 @@ void OpenGLDevice::SetErrorObject(Error* errptr, std::string_view prefix, GLenum std::unique_ptr 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 diff --git a/src/util/opengl_device.h b/src/util/opengl_device.h index d16c3b6d9..c3c1e4ee0 100644 --- a/src/util/opengl_device.h +++ b/src/util/opengl_device.h @@ -52,15 +52,18 @@ public: std::optional exclusive_fullscreen_control, Error* error) override; std::unique_ptr 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 CreateSampler(const GPUSampler::Config& config) override; - std::unique_ptr 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 CreateSampler(const GPUSampler::Config& config, Error* error = nullptr) override; + std::unique_ptr CreateTextureBuffer(GPUTextureBuffer::Format format, u32 size_in_elements, + Error* error = nullptr) override; - std::unique_ptr CreateDownloadTexture(u32 width, u32 height, GPUTexture::Format format) override; std::unique_ptr 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 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, diff --git a/src/util/opengl_stream_buffer.cpp b/src/util/opengl_stream_buffer.cpp index f31ebf8e7..212a17187 100644 --- a/src/util/opengl_stream_buffer.cpp +++ b/src/util/opengl_stream_buffer.cpp @@ -5,9 +5,9 @@ #include "common/align.h" #include "common/assert.h" +#include "common/error.h" #include -#include 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 Create(GLenum target, u32 size) + static std::unique_ptr 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 Create(GLenum target, u32 size) + static std::unique_ptr 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 Create(GLenum target, u32 size, bool coherent = true) + static std::unique_ptr 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::Create(GLenum target, u32 size) +std::unique_ptr OpenGLStreamBuffer::Create(GLenum target, u32 size, Error* error /* = nullptr */) { std::unique_ptr 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::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 } diff --git a/src/util/opengl_stream_buffer.h b/src/util/opengl_stream_buffer.h index 7ae779eec..fa0bca26d 100644 --- a/src/util/opengl_stream_buffer.h +++ b/src/util/opengl_stream_buffer.h @@ -12,6 +12,8 @@ #include #include +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 Create(GLenum target, u32 size); + static std::unique_ptr Create(GLenum target, u32 size, Error* error = nullptr); protected: OpenGLStreamBuffer(GLenum target, GLuint buffer_id, u32 size); diff --git a/src/util/opengl_texture.cpp b/src/util/opengl_texture.cpp index 00793421b..65e1d3ba9 100644 --- a/src/util/opengl_texture.cpp +++ b/src/util/opengl_texture.cpp @@ -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(width), static_cast(height), static_cast(layers), static_cast(levels), - static_cast(samples), type, format), + static_cast(samples), type, format, flags), m_id(id) { } @@ -126,14 +127,15 @@ bool OpenGLTexture::UseTextureStorage() const } std::unique_ptr 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::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(new OpenGLTexture(width, height, layers, levels, samples, type, format, id)); + return std::unique_ptr( + 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 OpenGLDevice::CreateSampler(const GPUSampler::Config& config) +std::unique_ptr OpenGLDevice::CreateSampler(const GPUSampler::Config& config, Error* error /* = nullptr */) { static constexpr std::array(GPUSampler::AddressMode::MaxCount)> ta = {{ GL_REPEAT, // Repeat @@ -433,7 +446,7 @@ std::unique_ptr 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 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 OpenGLDevice::CreateTextureBuffer(GPUTextureBu glGetInteger64v(GL_MAX_SHADER_STORAGE_BLOCK_SIZE, &max_ssbo_size); if (static_cast(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 buffer = OpenGLStreamBuffer::Create(target, buffer_size); + std::unique_ptr buffer = OpenGLStreamBuffer::Create(target, buffer_size, error); if (!buffer) return {}; buffer->Unbind(); @@ -726,7 +739,7 @@ std::unique_ptr 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::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::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::Create(u32 width, const bool imported = (memory != nullptr); u8* cpu_buffer = imported ? static_cast(memory) : static_cast(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( 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(name.length()), name.data()); } -std::unique_ptr OpenGLDevice::CreateDownloadTexture(u32 width, u32 height, - GPUTexture::Format format) +std::unique_ptr +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 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); } diff --git a/src/util/opengl_texture.h b/src/util/opengl_texture.h index 4a4dd03e8..5bc290c2b 100644 --- a/src/util/opengl_texture.h +++ b/src/util/opengl_texture.h @@ -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 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 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; diff --git a/src/util/postprocessing.cpp b/src/util/postprocessing.cpp index 29125e84a..02f208fc4 100644 --- a/src/util/postprocessing.cpp +++ b/src/util/postprocessing.cpp @@ -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."); diff --git a/src/util/postprocessing_shader_fx.cpp b/src/util/postprocessing_shader_fx.cpp index dc4234048..2f3f945e6 100644 --- a/src/util/postprocessing_shader_fx.cpp +++ b/src/util/postprocessing_shader_fx.cpp @@ -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,12 +1455,10 @@ bool PostProcessing::ReShadeFXShader::ResizeOutput(GPUTexture::Format format, u3 const u32 t_width = std::max(static_cast(static_cast(width) * tex.rt_scale), 1u); const u32 t_height = std::max(static_cast(static_cast(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; diff --git a/src/util/vulkan_device.cpp b/src/util/vulkan_device.cpp index 4a41a6818..11039075d 100644 --- a/src/util/vulkan_device.cpp +++ b/src/util/vulkan_device.cpp @@ -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(); + m_current_framebuffer = VK_NULL_HANDLE; if (m_num_current_render_targets == 0 && !m_current_depth_target) - { - m_current_framebuffer = VK_NULL_HANDLE; 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(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++) { diff --git a/src/util/vulkan_device.h b/src/util/vulkan_device.h index 43a982325..8ad11229a 100644 --- a/src/util/vulkan_device.h +++ b/src/util/vulkan_device.h @@ -88,15 +88,18 @@ public: std::optional exclusive_fullscreen_control, Error* error) override; std::unique_ptr 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 CreateSampler(const GPUSampler::Config& config) override; - std::unique_ptr 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 CreateSampler(const GPUSampler::Config& config, Error* error = nullptr) override; + std::unique_ptr CreateTextureBuffer(GPUTextureBuffer::Format format, u32 size_in_elements, + Error* error = nullptr) override; - std::unique_ptr CreateDownloadTexture(u32 width, u32 height, GPUTexture::Format format) override; std::unique_ptr 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 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(); diff --git a/src/util/vulkan_texture.cpp b/src/util/vulkan_texture.cpp index cb121ca44..12c833635 100644 --- a/src/util/vulkan_texture.cpp +++ b/src/util/vulkan_texture.cpp @@ -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(width), static_cast(height), static_cast(layers), static_cast(levels), - static_cast(samples), type, format), + static_cast(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::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::Create(u32 width, u32 height, u32 s_identity_swizzle, {VK_IMAGE_ASPECT_COLOR_BIT, 0, static_cast(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::Create(u32 width, u32 height, u32 } break; - case Type::RWTexture: - { - 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; + DefaultCaseIsUnreachable(); + } - default: - return {}; + if ((flags & Flags::AllowBindAsImage) != Flags::None) + { + DebugAssert(levels == 1); + ici.usage |= VK_IMAGE_USAGE_STORAGE_BIT; } // Use dedicated allocations for typical RT size @@ -146,14 +142,9 @@ std::unique_ptr 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::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( - 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(m_width >> src_level, 1u); + const u32 src_height = std::max(m_height >> src_level, 1u); + const u32 dst_width = std::max(m_width >> dst_level, 1u); + const u32 dst_height = std::max(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(src_width), static_cast(src_height), 1}}, // srcOffsets + {VK_IMAGE_ASPECT_COLOR_BIT, dst_level, 0u, 1u}, // dstSubresource + {{0, 0, 0}, {static_cast(dst_width), static_cast(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 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(format)]; std::unique_ptr 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 VulkanDevice::CreateSampler(const GPUSampler::Config& config) +std::unique_ptr 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 VulkanDevice::CreateTextureBuffer(GPUTextureBuffer::Format format, - u32 size_in_elements) + u32 size_in_elements, Error* error) { static constexpr std::array(GPUTextureBuffer::Format::MaxCount)> format_mapping = {{ VK_FORMAT_R16_UINT, // R16UI @@ -939,7 +971,7 @@ std::unique_ptr 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::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::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::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 VulkanDevice::CreateDownloadTexture(u32 width, u32 height, - GPUTexture::Format format) +std::unique_ptr +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 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); } diff --git a/src/util/vulkan_texture.h b/src/util/vulkan_texture.h index 3d7fcfa2f..f7dd8b601 100644 --- a/src/util/vulkan_texture.h +++ b/src/util/vulkan_texture.h @@ -38,7 +38,7 @@ public: ~VulkanTexture() override; static std::unique_ptr 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 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;