diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h index 691e3c9a4c9..0db26735d65 100644 --- a/intern/ghost/GHOST_Types.h +++ b/intern/ghost/GHOST_Types.h @@ -852,6 +852,18 @@ typedef struct { float colored_titlebar_bg_color[3]; } GHOST_WindowDecorationStyleSettings; +typedef struct { + /* Is HDR enabled for this Window? */ + bool hdr_enabled; + /* Scale factor to display SDR content in HDR. */ + float sdr_white_level; +} GHOST_WindowHDRInfo; + +#define GHOST_WINDOW_HDR_INFO_NONE \ + { \ + /*hdr_enabled*/ false, /*sdr_white_level*/ 1.0f, \ + } + #ifdef WITH_VULKAN_BACKEND typedef struct { /** Image handle to the image that will be presented to the user. */ @@ -866,6 +878,8 @@ typedef struct { VkSemaphore present_semaphore; /** Fence to signal after the image has been updated. */ VkFence submission_fence; + /* Factor to scale SDR content to HDR. */ + float sdr_scale; } GHOST_VulkanSwapChainData; typedef enum { diff --git a/intern/ghost/intern/GHOST_ContextVK.cc b/intern/ghost/intern/GHOST_ContextVK.cc index 1636a7660a5..6e893efcfa1 100644 --- a/intern/ghost/intern/GHOST_ContextVK.cc +++ b/intern/ghost/intern/GHOST_ContextVK.cc @@ -574,7 +574,8 @@ GHOST_ContextVK::GHOST_ContextVK(const GHOST_ContextParams &context_params, #endif int contextMajorVersion, int contextMinorVersion, - const GHOST_GPUDevice &preferred_device) + const GHOST_GPUDevice &preferred_device, + const GHOST_WindowHDRInfo *hdr_info) : GHOST_Context(context_params), #ifdef _WIN32 hwnd_(hwnd), @@ -593,6 +594,7 @@ GHOST_ContextVK::GHOST_ContextVK(const GHOST_ContextParams &context_params, context_major_version_(contextMajorVersion), context_minor_version_(contextMinorVersion), preferred_device_(preferred_device), + hdr_info_(hdr_info), surface_(VK_NULL_HANDLE), swapchain_(VK_NULL_HANDLE), frame_data_(GHOST_FRAMES_IN_FLIGHT), @@ -644,7 +646,7 @@ GHOST_TSuccess GHOST_ContextVK::swapBuffers() * has been signaled and waited for. */ vkWaitForFences(device, 1, &submission_frame_data.submission_fence, true, UINT64_MAX); submission_frame_data.discard_pile.destroy(device); - bool use_hdr_swapchain = false; + bool use_hdr_swapchain = true; #ifdef WITH_GHOST_WAYLAND /* Wayland doesn't provide a WSI with windowing capabilities, therefore cannot detect whether the * swap-chain needs to be recreated. But as a side effect we can recreate the swap-chain before @@ -720,6 +722,7 @@ GHOST_TSuccess GHOST_ContextVK::swapBuffers() swap_chain_data.submission_fence = submission_frame_data.submission_fence; swap_chain_data.acquire_semaphore = submission_frame_data.acquire_semaphore; swap_chain_data.present_semaphore = swapchain_image.present_semaphore; + swap_chain_data.sdr_scale = (hdr_info_) ? hdr_info_->sdr_white_level : 1.0f; vkResetFences(device, 1, &submission_frame_data.submission_fence); if (swap_buffers_pre_callback_) { @@ -767,6 +770,7 @@ GHOST_TSuccess GHOST_ContextVK::getVulkanSwapChainFormat( r_swap_chain_data->image = VK_NULL_HANDLE; r_swap_chain_data->surface_format = surface_format_; r_swap_chain_data->extent = render_extent_; + r_swap_chain_data->sdr_scale = (hdr_info_) ? hdr_info_->sdr_white_level : 1.0f; return GHOST_kSuccess; } @@ -915,7 +919,7 @@ static bool selectSurfaceFormat(const VkPhysicalDevice physical_device, vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &format_count, formats.data()); array, 4> selection_order = { - make_pair(VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT, VK_FORMAT_R16G16B16A16_SFLOAT), + make_pair(VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT, VK_FORMAT_R16G16B16A16_SFLOAT), make_pair(VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, VK_FORMAT_R16G16B16A16_SFLOAT), make_pair(VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, VK_FORMAT_R8G8B8A8_UNORM), make_pair(VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, VK_FORMAT_B8G8R8A8_UNORM), @@ -1119,7 +1123,7 @@ GHOST_TSuccess GHOST_ContextVK::recreateSwapchain(bool use_hdr_swapchain) create_info.imageColorSpace = surface_format_.colorSpace; create_info.imageExtent = render_extent_; create_info.imageArrayLayers = 1; - create_info.imageUsage = VK_IMAGE_USAGE_TRANSFER_DST_BIT; + create_info.imageUsage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_STORAGE_BIT; create_info.preTransform = capabilities.currentTransform; create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; create_info.presentMode = present_mode; @@ -1226,6 +1230,7 @@ GHOST_TSuccess GHOST_ContextVK::initializeDrawingContext() bool use_hdr_swapchain = false; #ifdef _WIN32 const bool use_window_surface = (hwnd_ != nullptr); + use_hdr_swapchain = true; #elif defined(__APPLE__) const bool use_window_surface = (metal_layer_ != nullptr); #else /* UNIX/Linux */ @@ -1281,6 +1286,13 @@ GHOST_TSuccess GHOST_ContextVK::initializeDrawingContext() VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME); optional_device_extensions.push_back(VK_EXT_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME); } + + const bool use_swapchain_colorspace = contains_extension( + extensions_available, VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME); + if (use_swapchain_colorspace) { + requireExtension( + extensions_available, extensions_enabled, VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME); + } } /* External memory extensions. */ diff --git a/intern/ghost/intern/GHOST_ContextVK.hh b/intern/ghost/intern/GHOST_ContextVK.hh index 40558ffd1ed..2582f23c1cc 100644 --- a/intern/ghost/intern/GHOST_ContextVK.hh +++ b/intern/ghost/intern/GHOST_ContextVK.hh @@ -127,7 +127,8 @@ class GHOST_ContextVK : public GHOST_Context { #endif int contextMajorVersion, int contextMinorVersion, - const GHOST_GPUDevice &preferred_device); + const GHOST_GPUDevice &preferred_device, + const GHOST_WindowHDRInfo *hdr_info_ = nullptr); /** * Destructor. @@ -230,6 +231,9 @@ class GHOST_ContextVK : public GHOST_Context { const int context_minor_version_; const GHOST_GPUDevice preferred_device_; + /* Optional HDR info updated by window. */ + const GHOST_WindowHDRInfo *hdr_info_; + /* For display only. */ VkSurfaceKHR surface_; VkSwapchainKHR swapchain_; diff --git a/intern/ghost/intern/GHOST_SystemWin32.cc b/intern/ghost/intern/GHOST_SystemWin32.cc index 59e39d03efe..2a527915d75 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.cc +++ b/intern/ghost/intern/GHOST_SystemWin32.cc @@ -1434,6 +1434,8 @@ GHOST_Event *GHOST_SystemWin32::processWindowSizeEvent(GHOST_WindowWin32 *window system->dispatchEvents(); return nullptr; } + + window->updateHDRInfo(); return sizeEvent; } @@ -2159,6 +2161,9 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, uint msg, WPARAM wParam, if (LOWORD(wParam) == WA_INACTIVE) { window->lostMouseCapture(); } + else { + window->updateHDRInfo(); + } lResult = ::DefWindowProc(hwnd, msg, wParam, lParam); break; @@ -2176,6 +2181,7 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, uint msg, WPARAM wParam, } case WM_EXITSIZEMOVE: { window->in_live_resize_ = 0; + window->updateHDRInfo(); break; } case WM_PAINT: { @@ -2240,6 +2246,7 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, uint msg, WPARAM wParam, } else { event = processWindowEvent(GHOST_kEventWindowMove, window); + window->updateHDRInfo(); } break; @@ -2275,6 +2282,7 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, uint msg, WPARAM wParam, if (wt) { wt->remapCoordinates(); } + window->updateHDRInfo(); break; } case WM_KILLFOCUS: { @@ -2293,6 +2301,7 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, uint msg, WPARAM wParam, { window->ThemeRefresh(); } + window->updateHDRInfo(); break; } /* ====================== diff --git a/intern/ghost/intern/GHOST_WindowWin32.cc b/intern/ghost/intern/GHOST_WindowWin32.cc index 9a72007d791..1b92e7d0a4c 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.cc +++ b/intern/ghost/intern/GHOST_WindowWin32.cc @@ -218,6 +218,9 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, /* Initialize Direct Manipulation. */ direct_manipulation_helper_ = GHOST_DirectManipulationHelper::create(h_wnd_, getDPIHint()); + + /* Initialize HDR info. */ + updateHDRInfo(); } void GHOST_WindowWin32::updateDirectManipulation() @@ -619,7 +622,7 @@ GHOST_Context *GHOST_WindowWin32::newDrawingContext(GHOST_TDrawingContextType ty #ifdef WITH_VULKAN_BACKEND case GHOST_kDrawingContextTypeVulkan: { GHOST_Context *context = new GHOST_ContextVK( - want_context_params_, h_wnd_, 1, 2, preferred_device_); + want_context_params_, h_wnd_, 1, 2, preferred_device_, &hdr_info_); if (context->initializeDrawingContext()) { return context; } @@ -1262,3 +1265,87 @@ void GHOST_WindowWin32::unregisterWindowAppUserModelProperties() pstore->Release(); } } + +/* We call this from a few window event changes, but actually none of them immediately + * respond to SDR white level changes in the system. That requires using the WinRT API, + * which we don't do so far. */ +void GHOST_WindowWin32::updateHDRInfo() +{ + /* Get monitor from window. */ + HMONITOR hmonitor = ::MonitorFromWindow(h_wnd_, MONITOR_DEFAULTTONEAREST); + if (!hmonitor) { + return; + } + + MONITORINFOEXW monitor_info = {}; + monitor_info.cbSize = sizeof(MONITORINFOEXW); + if (!::GetMonitorInfoW(hmonitor, &monitor_info)) { + return; + } + + /* Get active display paths and modes. */ + UINT32 path_count = 0; + UINT32 mode_count = 0; + if (::GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &path_count, &mode_count) != + ERROR_SUCCESS) + { + return; + } + + std::vector paths(path_count); + std::vector modes(mode_count); + if (::QueryDisplayConfig( + QDC_ONLY_ACTIVE_PATHS, &path_count, paths.data(), &mode_count, modes.data(), nullptr) != + ERROR_SUCCESS) + { + return; + } + + GHOST_WindowHDRInfo info = GHOST_WINDOW_HDR_INFO_NONE; + + /* Find the display path matching the monitor. */ + for (const DISPLAYCONFIG_PATH_INFO &path : paths) { + DISPLAYCONFIG_SOURCE_DEVICE_NAME device_name = {}; + device_name.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME; + device_name.header.size = sizeof(device_name); + device_name.header.adapterId = path.sourceInfo.adapterId; + device_name.header.id = path.sourceInfo.id; + + if (::DisplayConfigGetDeviceInfo(&device_name.header) != ERROR_SUCCESS) { + continue; + } + if (wcscmp(monitor_info.szDevice, device_name.viewGdiDeviceName) != 0) { + continue; + } + + /* Query HDR status. */ + DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO color_info = {}; + color_info.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO; + color_info.header.size = sizeof(color_info); + color_info.header.adapterId = path.targetInfo.adapterId; + color_info.header.id = path.targetInfo.id; + + if (::DisplayConfigGetDeviceInfo(&color_info.header) == ERROR_SUCCESS) { + info.hdr_enabled = color_info.advancedColorSupported && color_info.advancedColorEnabled; + } + + if (info.hdr_enabled) { + /* Query SDR white level. */ + DISPLAYCONFIG_SDR_WHITE_LEVEL white_level = {}; + white_level.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL; + white_level.header.size = sizeof(white_level); + white_level.header.adapterId = path.targetInfo.adapterId; + white_level.header.id = path.targetInfo.id; + + if (::DisplayConfigGetDeviceInfo(&white_level.header) == ERROR_SUCCESS) { + if (white_level.SDRWhiteLevel > 0) { + /* Windows assumes 1.0 = 80 nits, so multipley by that to get the absolute + * value in nits if we need it in the future. */ + info.sdr_white_level = static_cast(white_level.SDRWhiteLevel) / 1000.0f; + } + } + } + + hdr_info_ = info; + } +} diff --git a/intern/ghost/intern/GHOST_WindowWin32.hh b/intern/ghost/intern/GHOST_WindowWin32.hh index 73c3dd3be54..624515fe1ff 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.hh +++ b/intern/ghost/intern/GHOST_WindowWin32.hh @@ -326,6 +326,9 @@ class GHOST_WindowWin32 : public GHOST_Window { GHOST_TTrackpadInfo getTrackpadInfo(); + /* Update HDR info on initialization and window changes. */ + void updateHDRInfo(); + private: /** * \param type: The type of rendering context create. @@ -412,6 +415,8 @@ class GHOST_WindowWin32 : public GHOST_Window { GHOST_DirectManipulationHelper *direct_manipulation_helper_; + GHOST_WindowHDRInfo hdr_info_ = GHOST_WINDOW_HDR_INFO_NONE; + #ifdef WITH_INPUT_IME /** Handle input method editors event */ GHOST_ImeWin32 ime_input_; diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index ade8f3a911d..5805a826b2d 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -29,6 +29,7 @@ set(INC ../draw/intern ../draw/intern/shaders metal/kernels + vulkan/shaders shaders/infos @@ -674,6 +675,10 @@ set(MSL_SRC shaders/metal/mtl_shader_common.msl ) +set(VULKAN_BACKEND_GLSL_SRC + vulkan/shaders/vk_backbuffer_blit_comp.glsl +) + if(WITH_GTESTS) if(WITH_GPU_BACKEND_TESTS) list(APPEND GLSL_SRC ${GLSL_SRC_TEST}) @@ -689,6 +694,10 @@ if(WITH_METAL_BACKEND) endforeach() endif() +if(WITH_VULKAN_BACKEND) + list(APPEND GLSL_SRC ${VULKAN_BACKEND_GLSL_SRC}) +endif() + set(GLSL_C) foreach(GLSL_FILE ${GLSL_SRC}) glsl_to_c(${GLSL_FILE} GLSL_C) diff --git a/source/blender/gpu/intern/gpu_shader_create_info_list.hh b/source/blender/gpu/intern/gpu_shader_create_info_list.hh index 935d4e9be6d..2d748207da1 100644 --- a/source/blender/gpu/intern/gpu_shader_create_info_list.hh +++ b/source/blender/gpu/intern/gpu_shader_create_info_list.hh @@ -50,6 +50,10 @@ # include "gpu_shader_fullscreen_blit_info.hh" #endif +#ifdef WITH_VULKAN_BACKEND +# include "vk_backbuffer_blit_info.hh" +#endif + /* Compositor. */ #include "compositor_alpha_crop_info.hh" #include "compositor_bilateral_blur_info.hh" diff --git a/source/blender/gpu/shaders/CMakeLists.txt b/source/blender/gpu/shaders/CMakeLists.txt index afc99ea987d..ab7ec16c3bd 100644 --- a/source/blender/gpu/shaders/CMakeLists.txt +++ b/source/blender/gpu/shaders/CMakeLists.txt @@ -83,6 +83,14 @@ set(SRC_GLSL_COMP # gpu_shader_index_2d_array_tris.glsl ) +set(SRC_VULKAN_GLSL_COMP + vk_backbuffer_blit_comp.glsl +) + +if(WITH_VULKAN_BACKEND) + list(APPEND SRC_GLSL_COMP ${SRC_VULKAN_GLSL_COMP}) +endif() + set(SRC_GLSL_LIB common/gpu_shader_print_lib.glsl ) diff --git a/source/blender/gpu/vulkan/shaders/vk_backbuffer_blit_comp.glsl b/source/blender/gpu/vulkan/shaders/vk_backbuffer_blit_comp.glsl new file mode 100644 index 00000000000..c5c589041d8 --- /dev/null +++ b/source/blender/gpu/vulkan/shaders/vk_backbuffer_blit_comp.glsl @@ -0,0 +1,25 @@ +/* SPDX-FileCopyrightText: 2025 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "vk_backbuffer_blit_info.hh" + +COMPUTE_SHADER_CREATE_INFO(vk_backbuffer_blit) + +void main() +{ + ivec2 dst_texel = ivec2(gl_GlobalInvocationID.xy); + ivec2 src_size = ivec2(imageSize(src_img)); + ivec2 src_texel = ivec2(dst_texel.x, src_size.y - dst_texel.y - 1); + vec4 color = imageLoad(src_img, ivec2(src_texel)); + /* + * Convert from extended sRGB non-linear to linear. + * + * Preserves negative wide gamut values with sign/abs. + * Gamma 2.2 is used instead of the sRGB piecewise transfer function, because + * most SDR sRGB displays decode with gamma 2.2, and that's what we are trying + * to match. + */ + color.rgb = sign(color.rgb) * pow(abs(color.rgb), vec3(2.2f)) * sdr_scale; + imageStore(dst_img, ivec2(dst_texel), color); +} diff --git a/source/blender/gpu/vulkan/shaders/vk_backbuffer_blit_info.hh b/source/blender/gpu/vulkan/shaders/vk_backbuffer_blit_info.hh new file mode 100644 index 00000000000..844a0b7495c --- /dev/null +++ b/source/blender/gpu/vulkan/shaders/vk_backbuffer_blit_info.hh @@ -0,0 +1,15 @@ +/* SPDX-FileCopyrightText: 2025 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "gpu_shader_create_info.hh" + +GPU_SHADER_CREATE_INFO(vk_backbuffer_blit) +LOCAL_GROUP_SIZE(16, 16) +IMAGE(0, SFLOAT_16_16_16_16, read, Float2D, src_img) +IMAGE(1, SFLOAT_16_16_16_16, write, Float2D, dst_img) +PUSH_CONSTANT(float, sdr_scale) +COMPUTE_SOURCE("vk_backbuffer_blit_comp.glsl") +ADDITIONAL_INFO(gpu_srgb_to_framebuffer_space) +DO_STATIC_COMPILATION() +GPU_SHADER_CREATE_END() diff --git a/source/blender/gpu/vulkan/vk_context.cc b/source/blender/gpu/vulkan/vk_context.cc index f7b8b6f4bdb..e6abd814e21 100644 --- a/source/blender/gpu/vulkan/vk_context.cc +++ b/source/blender/gpu/vulkan/vk_context.cc @@ -89,7 +89,7 @@ void VKContext::sync_backbuffer(bool cycle_resource_pool) swap_chain_data.extent.height, 1, to_gpu_format(swap_chain_data.surface_format.format), - GPU_TEXTURE_USAGE_ATTACHMENT, + GPU_TEXTURE_USAGE_ATTACHMENT | GPU_TEXTURE_USAGE_SHADER_READ, nullptr); back_left->attachment_set(GPU_FB_COLOR_ATTACHMENT0, @@ -102,7 +102,7 @@ void VKContext::sync_backbuffer(bool cycle_resource_pool) swap_chain_format_ = swap_chain_data.surface_format; GCaps.hdr_viewport_support = (swap_chain_format_.format == VK_FORMAT_R16G16B16A16_SFLOAT) && ELEM(swap_chain_format_.colorSpace, - VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT, + VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR); } } @@ -372,6 +372,8 @@ void VKContext::swap_buffers_post_callback() void VKContext::swap_buffers_pre_handler(const GHOST_VulkanSwapChainData &swap_chain_data) { const bool do_blit_to_swapchain = swap_chain_data.image != VK_NULL_HANDLE; + const bool use_shader = swap_chain_data.surface_format.colorSpace == + VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT; /* When swapchain is invalid/minimized we only flush the render graph to free GPU resources. */ if (!do_blit_to_swapchain) { @@ -387,28 +389,43 @@ void VKContext::swap_buffers_pre_handler(const GHOST_VulkanSwapChainData &swap_c device.resources.add_image(swap_chain_data.image, 1, "SwapchainImage"); GPU_debug_group_begin("BackBuffer.Blit"); + if (use_shader) { + VKTexture swap_chain_texture("swap_chain_texture"); + swap_chain_texture.init_swapchain(swap_chain_data.image, + to_gpu_format(swap_chain_data.surface_format.format)); + Shader *shader = device.vk_backbuffer_blit_sh_get(); + GPU_shader_bind(shader); + GPU_shader_uniform_1f(shader, "sdr_scale", swap_chain_data.sdr_scale); + VKStateManager &state_manager = state_manager_get(); + state_manager.image_bind(color_attachment, 0); + state_manager.image_bind(&swap_chain_texture, 1); + int2 dispatch_size = math::divide_ceil( + int2(swap_chain_data.extent.width, swap_chain_data.extent.height), int2(16)); + VKBackend::get().compute_dispatch(UNPACK2(dispatch_size), 1); + } + else { + render_graph::VKBlitImageNode::CreateInfo blit_image = {}; + blit_image.src_image = color_attachment->vk_image_handle(); + blit_image.dst_image = swap_chain_data.image; + blit_image.filter = VK_FILTER_LINEAR; - render_graph::VKBlitImageNode::CreateInfo blit_image = {}; - blit_image.src_image = color_attachment->vk_image_handle(); - blit_image.dst_image = swap_chain_data.image; - blit_image.filter = VK_FILTER_LINEAR; + VkImageBlit ®ion = blit_image.region; + region.srcOffsets[0] = {0, 0, 0}; + region.srcOffsets[1] = {color_attachment->width_get(), color_attachment->height_get(), 1}; + region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + region.srcSubresource.mipLevel = 0; + region.srcSubresource.baseArrayLayer = 0; + region.srcSubresource.layerCount = 1; - VkImageBlit ®ion = blit_image.region; - region.srcOffsets[0] = {0, 0, 0}; - region.srcOffsets[1] = {color_attachment->width_get(), color_attachment->height_get(), 1}; - region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - region.srcSubresource.mipLevel = 0; - region.srcSubresource.baseArrayLayer = 0; - region.srcSubresource.layerCount = 1; + region.dstOffsets[0] = {0, int32_t(swap_chain_data.extent.height), 0}; + region.dstOffsets[1] = {int32_t(swap_chain_data.extent.width), 0, 1}; + region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + region.dstSubresource.mipLevel = 0; + region.dstSubresource.baseArrayLayer = 0; + region.dstSubresource.layerCount = 1; - region.dstOffsets[0] = {0, int32_t(swap_chain_data.extent.height), 0}; - region.dstOffsets[1] = {int32_t(swap_chain_data.extent.width), 0, 1}; - region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - region.dstSubresource.mipLevel = 0; - region.dstSubresource.baseArrayLayer = 0; - region.dstSubresource.layerCount = 1; - - render_graph.add_node(blit_image); + render_graph.add_node(blit_image); + } render_graph::VKSynchronizationNode::CreateInfo synchronization = {}; synchronization.vk_image = swap_chain_data.image; diff --git a/source/blender/gpu/vulkan/vk_device.cc b/source/blender/gpu/vulkan/vk_device.cc index 3014a1902ab..c0aa2581e36 100644 --- a/source/blender/gpu/vulkan/vk_device.cc +++ b/source/blender/gpu/vulkan/vk_device.cc @@ -75,6 +75,7 @@ void VKDevice::deinit() dummy_buffer.free(); samplers_.free(); + GPU_SHADER_FREE_SAFE(vk_backbuffer_blit_sh_); { while (!thread_data_.is_empty()) { diff --git a/source/blender/gpu/vulkan/vk_device.hh b/source/blender/gpu/vulkan/vk_device.hh index 02ab4cfe8d9..b6be136f722 100644 --- a/source/blender/gpu/vulkan/vk_device.hh +++ b/source/blender/gpu/vulkan/vk_device.hh @@ -237,6 +237,8 @@ class VKDevice : public NonCopyable { std::string glsl_comp_patch_; Vector thread_data_; + Shader *vk_backbuffer_blit_sh_ = nullptr; + public: render_graph::VKResourceStateTracker resources; VKDiscardPool orphaned_data; @@ -479,6 +481,14 @@ class VKDevice : public NonCopyable { /** \} */ + Shader *vk_backbuffer_blit_sh_get() + { + if (vk_backbuffer_blit_sh_ == nullptr) { + vk_backbuffer_blit_sh_ = GPU_shader_create_from_info_name("vk_backbuffer_blit"); + } + return vk_backbuffer_blit_sh_; + } + private: void init_physical_device_properties(); void init_physical_device_memory_properties(); diff --git a/source/blender/gpu/vulkan/vk_texture.cc b/source/blender/gpu/vulkan/vk_texture.cc index 3364a82165d..34fa6764fc5 100644 --- a/source/blender/gpu/vulkan/vk_texture.cc +++ b/source/blender/gpu/vulkan/vk_texture.cc @@ -480,6 +480,15 @@ bool VKTexture::init_internal(gpu::Texture *src, return true; } +void VKTexture::init_swapchain(VkImage vk_image, TextureFormat format) +{ + device_format_ = format_ = format; + format_flag_ = to_format_flag(format); + vk_image_ = vk_image; + type_ = GPU_TEXTURE_2D; + usage_set(GPU_TEXTURE_USAGE_ATTACHMENT | GPU_TEXTURE_USAGE_SHADER_WRITE); +} + bool VKTexture::is_texture_view() const { return source_texture_ != nullptr; diff --git a/source/blender/gpu/vulkan/vk_texture.hh b/source/blender/gpu/vulkan/vk_texture.hh index ae2a3e10aaa..467866cfc95 100644 --- a/source/blender/gpu/vulkan/vk_texture.hh +++ b/source/blender/gpu/vulkan/vk_texture.hh @@ -30,6 +30,7 @@ ENUM_OPERATORS(VKImageViewFlags, VKImageViewFlags::NO_SWIZZLING) class VKTexture : public Texture { friend class VKDescriptorSetUpdator; + friend class VKContext; /** * Texture format how the texture is stored on the device. @@ -148,6 +149,8 @@ class VKTexture : public Texture { int mip_offset, int layer_offset, bool use_stencil) override; + /* Initialize VKTexture with a swapchain image. */ + void init_swapchain(VkImage vk_image, TextureFormat gpu_format); private: /** Is this texture a view of another texture. */