mirror of
https://github.com/blender/blender
synced 2026-09-29 04:37:17 +03:00
The new intersect_mnee kernel runs before shade_surface, and shade_surface_mnee is eliminated. That large kernel was causing problems for some GPU compilers. MNEE state is packed into a shadow path state to avoid significantly increasing the path state size. This shadow state is then either turned into an actual shadow ray state or discarded in shade_surface. MNEE was re-enabled on HIP RDNA2 as it works again now. Texture cache misses now also work correctly with MNEE. This adds some extra code to the regular shade_surface kernel even when MNEE is not used, to use the MNEE sampled point instead of sampling a light. But there seems to be no significant performance impact. Co-authored-by: Sergey Sharybin <sergey@blender.org> Pull Request: https://projects.blender.org/blender/blender/pulls/158698
168 lines
5 KiB
C++
168 lines
5 KiB
C++
/* SPDX-FileCopyrightText: 2025 Intel Corporation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0 */
|
|
|
|
#if defined(WITH_ONEAPI) && defined(SYCL_LINEAR_MEMORY_INTEROP_AVAILABLE)
|
|
|
|
# include "device/oneapi/graphics_interop.h"
|
|
|
|
# include "device/oneapi/device.h"
|
|
# include "device/oneapi/device_impl.h"
|
|
# include "device/oneapi/queue.h"
|
|
|
|
# include "session/display_driver.h"
|
|
|
|
# ifdef _WIN32
|
|
# include "util/windows.h"
|
|
# else
|
|
# include <unistd.h>
|
|
# endif
|
|
|
|
CCL_NAMESPACE_BEGIN
|
|
|
|
OneapiDeviceGraphicsInterop::OneapiDeviceGraphicsInterop(OneapiDeviceQueue *queue)
|
|
: queue_(queue), device_(static_cast<OneapiDevice *>(queue->device))
|
|
{
|
|
}
|
|
|
|
OneapiDeviceGraphicsInterop::~OneapiDeviceGraphicsInterop()
|
|
{
|
|
free();
|
|
}
|
|
|
|
void OneapiDeviceGraphicsInterop::set_buffer(GraphicsInteropBuffer &interop_buffer)
|
|
{
|
|
if (interop_buffer.is_empty()) {
|
|
free();
|
|
return;
|
|
}
|
|
|
|
need_zero_ |= interop_buffer.take_zero();
|
|
|
|
if (!interop_buffer.has_new_handle()) {
|
|
return;
|
|
}
|
|
|
|
free();
|
|
|
|
if (interop_buffer.get_type() != GraphicsInteropDevice::VULKAN) {
|
|
/* SYCL only supports interop with Vulkan and D3D. */
|
|
LOG_ERROR
|
|
<< "oneAPI interop set_buffer called for invalid graphics API. Only Vulkan is supported.";
|
|
return;
|
|
}
|
|
|
|
# ifdef _WIN32
|
|
/* import_external_memory will not take ownership of the handle. */
|
|
vulkan_windows_handle_ = reinterpret_cast<void *>(interop_buffer.take_handle());
|
|
auto sycl_mem_handle_type =
|
|
sycl::ext::oneapi::experimental::external_mem_handle_type::win32_nt_handle;
|
|
sycl::ext::oneapi::experimental::external_mem_descriptor<
|
|
sycl::ext::oneapi::experimental::resource_win32_handle>
|
|
sycl_external_mem_descriptor{{vulkan_windows_handle_}, sycl_mem_handle_type};
|
|
# else
|
|
/* import_external_memory will take ownership of the file descriptor. */
|
|
auto sycl_mem_handle_type = sycl::ext::oneapi::experimental::external_mem_handle_type::opaque_fd;
|
|
sycl::ext::oneapi::experimental::external_mem_descriptor<
|
|
sycl::ext::oneapi::experimental::resource_fd>
|
|
sycl_external_mem_descriptor{{static_cast<int>(interop_buffer.take_handle())},
|
|
sycl_mem_handle_type};
|
|
# endif
|
|
|
|
sycl::queue *sycl_queue = reinterpret_cast<sycl::queue *>(device_->sycl_queue());
|
|
try {
|
|
sycl_external_memory_ = sycl::ext::oneapi::experimental::import_external_memory(
|
|
sycl_external_mem_descriptor, *sycl_queue);
|
|
}
|
|
catch (sycl::exception &e) {
|
|
# ifdef _WIN32
|
|
CloseHandle(HANDLE(vulkan_windows_handle_));
|
|
vulkan_windows_handle_ = nullptr;
|
|
# else
|
|
close(sycl_external_mem_descriptor.external_resource.file_descriptor);
|
|
# endif
|
|
LOG_ERROR << "Error importing Vulkan memory: " << e.what();
|
|
return;
|
|
}
|
|
|
|
buffer_size_ = interop_buffer.get_size();
|
|
|
|
/* Like the CUDA/HIP backend, we map the buffer persistently. */
|
|
try {
|
|
sycl_memory_ptr_ = sycl::ext::oneapi::experimental::map_external_linear_memory(
|
|
sycl_external_memory_, 0, buffer_size_, *sycl_queue);
|
|
}
|
|
catch (sycl::exception &e) {
|
|
try {
|
|
sycl::ext::oneapi::experimental::release_external_memory(sycl_external_memory_, *sycl_queue);
|
|
}
|
|
catch (sycl::exception &e) {
|
|
LOG_ERROR << "Could not release external Vulkan memory: " << e.what();
|
|
}
|
|
sycl_external_memory_ = {};
|
|
buffer_size_ = 0;
|
|
/* Only need to close Windows handle, as file descriptor is owned by compute API. */
|
|
# ifdef _WIN32
|
|
CloseHandle(HANDLE(vulkan_windows_handle_));
|
|
vulkan_windows_handle_ = nullptr;
|
|
# endif
|
|
LOG_ERROR << "Error mapping external Vulkan memory: " << e.what();
|
|
return;
|
|
}
|
|
}
|
|
|
|
device_ptr OneapiDeviceGraphicsInterop::map()
|
|
{
|
|
if (sycl_memory_ptr_ && need_zero_) {
|
|
try {
|
|
/* We do not wait on the returned event here, as CUDA also uses "cuMemsetD8Async". */
|
|
sycl::queue *sycl_queue = reinterpret_cast<sycl::queue *>(device_->sycl_queue());
|
|
sycl_queue->memset(sycl_memory_ptr_, 0, buffer_size_);
|
|
}
|
|
catch (sycl::exception &e) {
|
|
LOG_ERROR << "Error clearing external Vulkan memory: " << e.what();
|
|
return device_ptr(0);
|
|
}
|
|
need_zero_ = false;
|
|
}
|
|
|
|
return reinterpret_cast<device_ptr>(sycl_memory_ptr_);
|
|
}
|
|
|
|
void OneapiDeviceGraphicsInterop::unmap() {}
|
|
|
|
void OneapiDeviceGraphicsInterop::free()
|
|
{
|
|
if (sycl_external_memory_.raw_handle) {
|
|
sycl::queue *sycl_queue = reinterpret_cast<sycl::queue *>(device_->sycl_queue());
|
|
try {
|
|
sycl::ext::oneapi::experimental::unmap_external_linear_memory(sycl_memory_ptr_, *sycl_queue);
|
|
}
|
|
catch (sycl::exception &e) {
|
|
LOG_ERROR << "Could not unmap external Vulkan memory: " << e.what();
|
|
}
|
|
try {
|
|
sycl::ext::oneapi::experimental::release_external_memory(sycl_external_memory_, *sycl_queue);
|
|
}
|
|
catch (sycl::exception &e) {
|
|
LOG_ERROR << "Could not release external Vulkan memory: " << e.what();
|
|
}
|
|
sycl_memory_ptr_ = {};
|
|
sycl_external_memory_ = {};
|
|
}
|
|
|
|
# ifdef _WIN32
|
|
if (vulkan_windows_handle_) {
|
|
CloseHandle(HANDLE(vulkan_windows_handle_));
|
|
vulkan_windows_handle_ = nullptr;
|
|
}
|
|
# endif
|
|
|
|
buffer_size_ = 0;
|
|
|
|
need_zero_ = false;
|
|
}
|
|
|
|
CCL_NAMESPACE_END
|
|
|
|
#endif
|