Add Chromium-only Blender WebEngine parity work
This commit is contained in:
360
blender-5.2.0/intern/cycles/device/cuda/device.cpp
Normal file
360
blender-5.2.0/intern/cycles/device/cuda/device.cpp
Normal file
@@ -0,0 +1,360 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#include "device/cuda/device.h"
|
||||
#include "device/device.h"
|
||||
|
||||
#include "util/log.h"
|
||||
|
||||
#ifdef WITH_CUDA
|
||||
# include "device/cuda/device_impl.h"
|
||||
|
||||
# include "integrator/denoiser_oidn_gpu.h" // IWYU pragma: keep
|
||||
|
||||
# include "util/string.h"
|
||||
# ifdef _WIN32
|
||||
# include "util/windows.h"
|
||||
# endif
|
||||
#endif /* WITH_CUDA */
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
bool device_cuda_init()
|
||||
{
|
||||
#if !defined(WITH_CUDA)
|
||||
return false;
|
||||
#elif defined(WITH_CUDA_DYNLOAD)
|
||||
static bool initialized = false;
|
||||
static bool result = false;
|
||||
|
||||
if (initialized) {
|
||||
return result;
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
int cuew_result = cuewInit(CUEW_INIT_CUDA);
|
||||
if (cuew_result == CUEW_SUCCESS) {
|
||||
LOG_INFO << "CUEW initialization succeeded";
|
||||
if (CUDADevice::have_precompiled_kernels()) {
|
||||
LOG_INFO << "Found precompiled kernels";
|
||||
result = true;
|
||||
}
|
||||
else if (cuewCompilerPath() != nullptr) {
|
||||
LOG_INFO << "Found CUDA compiler " << cuewCompilerPath();
|
||||
result = true;
|
||||
}
|
||||
else {
|
||||
LOG_INFO << "Neither precompiled kernels nor CUDA compiler was found,"
|
||||
<< " unable to use CUDA";
|
||||
}
|
||||
}
|
||||
else {
|
||||
LOG_WARNING << "CUEW initialization failed: "
|
||||
<< ((cuew_result == CUEW_ERROR_ATEXIT_FAILED) ?
|
||||
"Error setting up atexit() handler" :
|
||||
"Error opening the library");
|
||||
}
|
||||
|
||||
return result;
|
||||
#else /* WITH_CUDA_DYNLOAD */
|
||||
return true;
|
||||
#endif /* WITH_CUDA_DYNLOAD */
|
||||
}
|
||||
|
||||
unique_ptr<Device> device_cuda_create(const DeviceInfo &info,
|
||||
Stats &stats,
|
||||
Profiler &profiler,
|
||||
bool headless)
|
||||
{
|
||||
#ifdef WITH_CUDA
|
||||
return make_unique<CUDADevice>(info, stats, profiler, headless);
|
||||
#else
|
||||
(void)info;
|
||||
(void)stats;
|
||||
(void)profiler;
|
||||
(void)headless;
|
||||
|
||||
LOG_FATAL << "Request to create CUDA device without compiled-in support. Should never happen.";
|
||||
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef WITH_CUDA
|
||||
static CUresult device_cuda_safe_init()
|
||||
{
|
||||
# ifdef _WIN32
|
||||
__try
|
||||
{
|
||||
return cuInit(0);
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
/* Ignore crashes inside the CUDA driver and hope we can
|
||||
* survive even with corrupted CUDA installs. */
|
||||
fprintf(stderr, "Cycles CUDA: driver crashed, continuing without CUDA.\n");
|
||||
}
|
||||
|
||||
return CUDA_ERROR_NO_DEVICE;
|
||||
# else
|
||||
return cuInit(0);
|
||||
# endif
|
||||
}
|
||||
#endif /* WITH_CUDA */
|
||||
|
||||
void device_cuda_info(vector<DeviceInfo> &devices)
|
||||
{
|
||||
#ifdef WITH_CUDA
|
||||
CUresult result = device_cuda_safe_init();
|
||||
if (result != CUDA_SUCCESS) {
|
||||
if (result != CUDA_ERROR_NO_DEVICE) {
|
||||
LOG_ERROR << "CUDA cuInit: " << cuewErrorString(result);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
result = cuDeviceGetCount(&count);
|
||||
if (result != CUDA_SUCCESS) {
|
||||
LOG_ERROR << "CUDA cuDeviceGetCount: " << cuewErrorString(result);
|
||||
return;
|
||||
}
|
||||
|
||||
vector<DeviceInfo> display_devices;
|
||||
|
||||
for (int num = 0; num < count; num++) {
|
||||
char name[256];
|
||||
|
||||
result = cuDeviceGetName(name, 256, num);
|
||||
if (result != CUDA_SUCCESS) {
|
||||
LOG_ERROR << "CUDA cuDeviceGetName: " << cuewErrorString(result);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!cudaSupportsDevice(num)) {
|
||||
LOG_INFO << "Ignoring device \"" << name << "\", this graphics card is no longer supported.";
|
||||
continue;
|
||||
}
|
||||
|
||||
DeviceInfo info;
|
||||
|
||||
info.type = DEVICE_CUDA;
|
||||
info.description = string(name);
|
||||
info.num = num;
|
||||
|
||||
info.has_nanovdb = true;
|
||||
info.denoisers = 0;
|
||||
|
||||
info.has_gpu_queue = true;
|
||||
|
||||
/* Check if the device has P2P access to any other device in the system. */
|
||||
for (int peer_num = 0; peer_num < count && !info.has_peer_memory; peer_num++) {
|
||||
if (num != peer_num) {
|
||||
if (cudaSupportsDevice(peer_num)) {
|
||||
int can_access = 0;
|
||||
cuDeviceCanAccessPeer(&can_access, num, peer_num);
|
||||
info.has_peer_memory = (can_access != 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int pci_location[3] = {0, 0, 0};
|
||||
cuDeviceGetAttribute(&pci_location[0], CU_DEVICE_ATTRIBUTE_PCI_DOMAIN_ID, num);
|
||||
cuDeviceGetAttribute(&pci_location[1], CU_DEVICE_ATTRIBUTE_PCI_BUS_ID, num);
|
||||
cuDeviceGetAttribute(&pci_location[2], CU_DEVICE_ATTRIBUTE_PCI_DEVICE_ID, num);
|
||||
info.id = string_printf("CUDA_%s_%04x:%02x:%02x",
|
||||
name,
|
||||
(unsigned int)pci_location[0],
|
||||
(unsigned int)pci_location[1],
|
||||
(unsigned int)pci_location[2]);
|
||||
|
||||
# if defined(WITH_OPENIMAGEDENOISE)
|
||||
# if OIDN_VERSION >= 20300
|
||||
if (oidnIsCUDADeviceSupported(num)) {
|
||||
# else
|
||||
if (OIDNDenoiserGPU::is_device_supported(info)) {
|
||||
# endif
|
||||
info.denoisers |= DENOISER_OPENIMAGEDENOISE;
|
||||
}
|
||||
# endif
|
||||
|
||||
/* If device has a kernel timeout and no compute preemption, we assume
|
||||
* it is connected to a display and will freeze the display while doing
|
||||
* computations. */
|
||||
int timeout_attr = 0, preempt_attr = 0;
|
||||
cuDeviceGetAttribute(&timeout_attr, CU_DEVICE_ATTRIBUTE_KERNEL_EXEC_TIMEOUT, num);
|
||||
cuDeviceGetAttribute(&preempt_attr, CU_DEVICE_ATTRIBUTE_COMPUTE_PREEMPTION_SUPPORTED, num);
|
||||
|
||||
# ifdef _WIN32
|
||||
int major;
|
||||
cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, num);
|
||||
/* The CUDA driver reports compute preemption as not being available on
|
||||
* Windows 10 even when it is, due to an issue in application profiles.
|
||||
* Detect case where we expect it to be available and override. */
|
||||
if (preempt_attr == 0 && (major >= 6) && system_windows_version_at_least(10, 17134)) {
|
||||
LOG_INFO << "Assuming device has compute preemption on Windows 10.";
|
||||
preempt_attr = 1;
|
||||
}
|
||||
# endif
|
||||
|
||||
if (timeout_attr && !preempt_attr) {
|
||||
LOG_INFO << "Device is recognized as display.";
|
||||
info.description += " (Display)";
|
||||
info.display_device = true;
|
||||
display_devices.push_back(info);
|
||||
}
|
||||
else {
|
||||
LOG_INFO << "Device has compute preemption or is not used for display.";
|
||||
devices.push_back(info);
|
||||
}
|
||||
LOG_INFO << "Added device \"" << info.description << "\" with id \"" << info.id << "\".";
|
||||
|
||||
if (info.denoisers & DENOISER_OPENIMAGEDENOISE) {
|
||||
LOG_INFO << "Device with id \"" << info.id << "\" supports "
|
||||
<< denoiserTypeToHumanReadable(DENOISER_OPENIMAGEDENOISE) << ".";
|
||||
}
|
||||
}
|
||||
|
||||
if (!display_devices.empty()) {
|
||||
devices.insert(devices.end(), display_devices.begin(), display_devices.end());
|
||||
}
|
||||
#else /* WITH_CUDA */
|
||||
(void)devices;
|
||||
#endif /* WITH_CUDA */
|
||||
}
|
||||
|
||||
string device_cuda_capabilities()
|
||||
{
|
||||
#ifdef WITH_CUDA
|
||||
CUresult result = device_cuda_safe_init();
|
||||
if (result != CUDA_SUCCESS) {
|
||||
if (result != CUDA_ERROR_NO_DEVICE) {
|
||||
return string("Error initializing CUDA: ") + cuewErrorString(result);
|
||||
}
|
||||
return "No CUDA device found\n";
|
||||
}
|
||||
|
||||
int count;
|
||||
result = cuDeviceGetCount(&count);
|
||||
if (result != CUDA_SUCCESS) {
|
||||
return string("Error getting devices: ") + cuewErrorString(result);
|
||||
}
|
||||
|
||||
string capabilities;
|
||||
for (int num = 0; num < count; num++) {
|
||||
char name[256];
|
||||
if (cuDeviceGetName(name, 256, num) != CUDA_SUCCESS) {
|
||||
continue;
|
||||
}
|
||||
capabilities += string("\t") + name + "\n";
|
||||
int value;
|
||||
# define GET_ATTR(attr) \
|
||||
{ \
|
||||
if (cuDeviceGetAttribute(&value, CU_DEVICE_ATTRIBUTE_##attr, num) == CUDA_SUCCESS) { \
|
||||
capabilities += string_printf("\t\tCU_DEVICE_ATTRIBUTE_" #attr "\t\t\t%d\n", value); \
|
||||
} \
|
||||
} \
|
||||
(void)0
|
||||
/* TODO(sergey): Strip all attributes which are not useful for us
|
||||
* or does not depend on the driver.
|
||||
*/
|
||||
GET_ATTR(MAX_THREADS_PER_BLOCK);
|
||||
GET_ATTR(MAX_BLOCK_DIM_X);
|
||||
GET_ATTR(MAX_BLOCK_DIM_Y);
|
||||
GET_ATTR(MAX_BLOCK_DIM_Z);
|
||||
GET_ATTR(MAX_GRID_DIM_X);
|
||||
GET_ATTR(MAX_GRID_DIM_Y);
|
||||
GET_ATTR(MAX_GRID_DIM_Z);
|
||||
GET_ATTR(MAX_SHARED_MEMORY_PER_BLOCK);
|
||||
GET_ATTR(SHARED_MEMORY_PER_BLOCK);
|
||||
GET_ATTR(TOTAL_CONSTANT_MEMORY);
|
||||
GET_ATTR(WARP_SIZE);
|
||||
GET_ATTR(MAX_PITCH);
|
||||
GET_ATTR(MAX_REGISTERS_PER_BLOCK);
|
||||
GET_ATTR(REGISTERS_PER_BLOCK);
|
||||
GET_ATTR(CLOCK_RATE);
|
||||
GET_ATTR(TEXTURE_ALIGNMENT);
|
||||
GET_ATTR(GPU_OVERLAP);
|
||||
GET_ATTR(MULTIPROCESSOR_COUNT);
|
||||
GET_ATTR(KERNEL_EXEC_TIMEOUT);
|
||||
GET_ATTR(INTEGRATED);
|
||||
GET_ATTR(CAN_MAP_HOST_MEMORY);
|
||||
GET_ATTR(COMPUTE_MODE);
|
||||
GET_ATTR(MAXIMUM_TEXTURE1D_WIDTH);
|
||||
GET_ATTR(MAXIMUM_TEXTURE2D_WIDTH);
|
||||
GET_ATTR(MAXIMUM_TEXTURE2D_HEIGHT);
|
||||
GET_ATTR(MAXIMUM_TEXTURE3D_WIDTH);
|
||||
GET_ATTR(MAXIMUM_TEXTURE3D_HEIGHT);
|
||||
GET_ATTR(MAXIMUM_TEXTURE3D_DEPTH);
|
||||
GET_ATTR(MAXIMUM_TEXTURE2D_LAYERED_WIDTH);
|
||||
GET_ATTR(MAXIMUM_TEXTURE2D_LAYERED_HEIGHT);
|
||||
GET_ATTR(MAXIMUM_TEXTURE2D_LAYERED_LAYERS);
|
||||
GET_ATTR(MAXIMUM_TEXTURE2D_ARRAY_WIDTH);
|
||||
GET_ATTR(MAXIMUM_TEXTURE2D_ARRAY_HEIGHT);
|
||||
GET_ATTR(MAXIMUM_TEXTURE2D_ARRAY_NUMSLICES);
|
||||
GET_ATTR(SURFACE_ALIGNMENT);
|
||||
GET_ATTR(CONCURRENT_KERNELS);
|
||||
GET_ATTR(ECC_ENABLED);
|
||||
GET_ATTR(TCC_DRIVER);
|
||||
GET_ATTR(MEMORY_CLOCK_RATE);
|
||||
GET_ATTR(GLOBAL_MEMORY_BUS_WIDTH);
|
||||
GET_ATTR(L2_CACHE_SIZE);
|
||||
GET_ATTR(MAX_THREADS_PER_MULTIPROCESSOR);
|
||||
GET_ATTR(ASYNC_ENGINE_COUNT);
|
||||
GET_ATTR(UNIFIED_ADDRESSING);
|
||||
GET_ATTR(MAXIMUM_TEXTURE1D_LAYERED_WIDTH);
|
||||
GET_ATTR(MAXIMUM_TEXTURE1D_LAYERED_LAYERS);
|
||||
GET_ATTR(CAN_TEX2D_GATHER);
|
||||
GET_ATTR(MAXIMUM_TEXTURE2D_GATHER_WIDTH);
|
||||
GET_ATTR(MAXIMUM_TEXTURE2D_GATHER_HEIGHT);
|
||||
GET_ATTR(MAXIMUM_TEXTURE3D_WIDTH_ALTERNATE);
|
||||
GET_ATTR(MAXIMUM_TEXTURE3D_HEIGHT_ALTERNATE);
|
||||
GET_ATTR(MAXIMUM_TEXTURE3D_DEPTH_ALTERNATE);
|
||||
GET_ATTR(TEXTURE_PITCH_ALIGNMENT);
|
||||
GET_ATTR(MAXIMUM_TEXTURECUBEMAP_WIDTH);
|
||||
GET_ATTR(MAXIMUM_TEXTURECUBEMAP_LAYERED_WIDTH);
|
||||
GET_ATTR(MAXIMUM_TEXTURECUBEMAP_LAYERED_LAYERS);
|
||||
GET_ATTR(MAXIMUM_SURFACE1D_WIDTH);
|
||||
GET_ATTR(MAXIMUM_SURFACE2D_WIDTH);
|
||||
GET_ATTR(MAXIMUM_SURFACE2D_HEIGHT);
|
||||
GET_ATTR(MAXIMUM_SURFACE3D_WIDTH);
|
||||
GET_ATTR(MAXIMUM_SURFACE3D_HEIGHT);
|
||||
GET_ATTR(MAXIMUM_SURFACE3D_DEPTH);
|
||||
GET_ATTR(MAXIMUM_SURFACE1D_LAYERED_WIDTH);
|
||||
GET_ATTR(MAXIMUM_SURFACE1D_LAYERED_LAYERS);
|
||||
GET_ATTR(MAXIMUM_SURFACE2D_LAYERED_WIDTH);
|
||||
GET_ATTR(MAXIMUM_SURFACE2D_LAYERED_HEIGHT);
|
||||
GET_ATTR(MAXIMUM_SURFACE2D_LAYERED_LAYERS);
|
||||
GET_ATTR(MAXIMUM_SURFACECUBEMAP_WIDTH);
|
||||
GET_ATTR(MAXIMUM_SURFACECUBEMAP_LAYERED_WIDTH);
|
||||
GET_ATTR(MAXIMUM_SURFACECUBEMAP_LAYERED_LAYERS);
|
||||
GET_ATTR(MAXIMUM_TEXTURE1D_LINEAR_WIDTH);
|
||||
GET_ATTR(MAXIMUM_TEXTURE2D_LINEAR_WIDTH);
|
||||
GET_ATTR(MAXIMUM_TEXTURE2D_LINEAR_HEIGHT);
|
||||
GET_ATTR(MAXIMUM_TEXTURE2D_LINEAR_PITCH);
|
||||
GET_ATTR(MAXIMUM_TEXTURE2D_MIPMAPPED_WIDTH);
|
||||
GET_ATTR(MAXIMUM_TEXTURE2D_MIPMAPPED_HEIGHT);
|
||||
GET_ATTR(COMPUTE_CAPABILITY_MAJOR);
|
||||
GET_ATTR(COMPUTE_CAPABILITY_MINOR);
|
||||
GET_ATTR(MAXIMUM_TEXTURE1D_MIPMAPPED_WIDTH);
|
||||
GET_ATTR(STREAM_PRIORITIES_SUPPORTED);
|
||||
GET_ATTR(GLOBAL_L1_CACHE_SUPPORTED);
|
||||
GET_ATTR(LOCAL_L1_CACHE_SUPPORTED);
|
||||
GET_ATTR(MAX_SHARED_MEMORY_PER_MULTIPROCESSOR);
|
||||
GET_ATTR(MAX_REGISTERS_PER_MULTIPROCESSOR);
|
||||
GET_ATTR(MANAGED_MEMORY);
|
||||
GET_ATTR(MULTI_GPU_BOARD);
|
||||
GET_ATTR(MULTI_GPU_BOARD_GROUP_ID);
|
||||
# undef GET_ATTR
|
||||
capabilities += "\n";
|
||||
}
|
||||
|
||||
return capabilities;
|
||||
|
||||
#else /* WITH_CUDA */
|
||||
return "";
|
||||
#endif /* WITH_CUDA */
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
29
blender-5.2.0/intern/cycles/device/cuda/device.h
Normal file
29
blender-5.2.0/intern/cycles/device/cuda/device.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "util/string.h"
|
||||
#include "util/unique_ptr.h"
|
||||
#include "util/vector.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
class Device;
|
||||
class DeviceInfo;
|
||||
class Profiler;
|
||||
class Stats;
|
||||
|
||||
bool device_cuda_init();
|
||||
|
||||
unique_ptr<Device> device_cuda_create(const DeviceInfo &info,
|
||||
Stats &stats,
|
||||
Profiler &profiler,
|
||||
bool headless);
|
||||
|
||||
void device_cuda_info(vector<DeviceInfo> &devices);
|
||||
|
||||
string device_cuda_capabilities();
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
1099
blender-5.2.0/intern/cycles/device/cuda/device_impl.cpp
Normal file
1099
blender-5.2.0/intern/cycles/device/cuda/device_impl.cpp
Normal file
File diff suppressed because it is too large
Load Diff
111
blender-5.2.0/intern/cycles/device/cuda/device_impl.h
Normal file
111
blender-5.2.0/intern/cycles/device/cuda/device_impl.h
Normal file
@@ -0,0 +1,111 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#ifdef WITH_CUDA
|
||||
|
||||
# include "device/cuda/kernel.h"
|
||||
# include "device/cuda/queue.h"
|
||||
# include "device/cuda/util.h"
|
||||
# include "device/device.h"
|
||||
|
||||
# ifdef WITH_CUDA_DYNLOAD
|
||||
# include "cuew.h"
|
||||
# else
|
||||
# include <cuda.h>
|
||||
# include <cudaGL.h>
|
||||
# endif
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
class DeviceQueue;
|
||||
|
||||
class CUDADevice : public GPUDevice {
|
||||
|
||||
friend class CUDAContextScope;
|
||||
|
||||
public:
|
||||
CUdevice cuDevice;
|
||||
CUcontext cuContext;
|
||||
CUmodule cuModule;
|
||||
int pitch_alignment;
|
||||
int cuDevId;
|
||||
int cuDevArchitecture;
|
||||
bool first_error;
|
||||
|
||||
CUDADeviceKernels kernels;
|
||||
|
||||
static bool have_precompiled_kernels();
|
||||
|
||||
BVHLayoutMask get_bvh_layout_mask(uint /*kernel_features*/) const override;
|
||||
|
||||
void set_error(const string &error) override;
|
||||
|
||||
CUDADevice(const DeviceInfo &info, Stats &stats, Profiler &profiler, bool headless);
|
||||
|
||||
~CUDADevice() override;
|
||||
|
||||
bool support_device(const uint /*kernel_features*/);
|
||||
|
||||
bool check_peer_access(Device *peer_device) override;
|
||||
|
||||
bool use_adaptive_compilation();
|
||||
|
||||
string compile_kernel_get_common_cflags(const uint kernel_features);
|
||||
|
||||
string compile_kernel(const string &cflags, const char *name, bool optix = false);
|
||||
|
||||
bool load_kernels(const uint kernel_features) override;
|
||||
void reserve_local_memory(const uint kernel_features);
|
||||
|
||||
/* All memory types. */
|
||||
void mem_alloc(device_memory &mem) override;
|
||||
void mem_copy_to(device_memory &mem) override;
|
||||
void mem_move_to_host(device_memory &mem) override;
|
||||
void mem_copy_from(
|
||||
device_memory &mem, const size_t y, size_t w, const size_t h, size_t elem) override;
|
||||
void mem_zero(device_memory &mem) override;
|
||||
void mem_free(device_memory &mem) override;
|
||||
|
||||
device_ptr mem_alloc_sub_ptr(device_memory &mem, const size_t offset, size_t /*size*/) override;
|
||||
|
||||
/* Global memory. */
|
||||
void global_alloc(device_memory &mem);
|
||||
void global_copy_to(device_memory &mem);
|
||||
void global_free(device_memory &mem);
|
||||
|
||||
/* Image memory. */
|
||||
void image_alloc(device_image &mem);
|
||||
void image_copy_to(device_image &mem);
|
||||
void image_free(device_image &mem);
|
||||
|
||||
/* Device side memory. */
|
||||
void get_device_memory_info(size_t &total, size_t &free) override;
|
||||
bool alloc_device(void *&device_pointer, const size_t size) override;
|
||||
void free_device(void *device_pointer) override;
|
||||
|
||||
/* Shared memory. */
|
||||
bool shared_alloc(void *&shared_pointer, const size_t size) override;
|
||||
void shared_free(void *shared_pointer) override;
|
||||
void *shared_to_device_pointer(const void *shared_pointer) override;
|
||||
|
||||
/* Memory copy. */
|
||||
void copy_host_to_device(void *device_pointer, void *host_pointer, const size_t size) override;
|
||||
void const_copy_to(const char *name, void *host, const size_t size) override;
|
||||
|
||||
bool should_use_graphics_interop(const GraphicsInteropDevice &interop_device,
|
||||
const bool log) override;
|
||||
|
||||
unique_ptr<DeviceQueue> gpu_queue_create() override;
|
||||
|
||||
int get_num_multiprocessors();
|
||||
int get_max_num_threads_per_multiprocessor();
|
||||
|
||||
protected:
|
||||
bool get_device_attribute(CUdevice_attribute attribute, int *value);
|
||||
int get_device_default_attribute(CUdevice_attribute attribute, const int default_value);
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
186
blender-5.2.0/intern/cycles/device/cuda/graphics_interop.cpp
Normal file
186
blender-5.2.0/intern/cycles/device/cuda/graphics_interop.cpp
Normal file
@@ -0,0 +1,186 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#ifdef WITH_CUDA
|
||||
|
||||
# include "device/cuda/graphics_interop.h"
|
||||
|
||||
# include "device/cuda/device_impl.h"
|
||||
# include "device/cuda/util.h"
|
||||
|
||||
# include "session/display_driver.h"
|
||||
|
||||
# ifdef _WIN32
|
||||
# include "util/windows.h"
|
||||
# else
|
||||
# include <unistd.h>
|
||||
# endif
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
CUDADeviceGraphicsInterop::CUDADeviceGraphicsInterop(CUDADeviceQueue *queue)
|
||||
: queue_(queue), device_(static_cast<CUDADevice *>(queue->device))
|
||||
{
|
||||
}
|
||||
|
||||
CUDADeviceGraphicsInterop::~CUDADeviceGraphicsInterop()
|
||||
{
|
||||
CUDAContextScope scope(device_);
|
||||
free();
|
||||
}
|
||||
|
||||
void CUDADeviceGraphicsInterop::set_buffer(GraphicsInteropBuffer &interop_buffer)
|
||||
{
|
||||
CUDAContextScope scope(device_);
|
||||
|
||||
if (interop_buffer.is_empty()) {
|
||||
free();
|
||||
return;
|
||||
}
|
||||
|
||||
need_zero_ |= interop_buffer.take_zero();
|
||||
|
||||
if (!interop_buffer.has_new_handle()) {
|
||||
return;
|
||||
}
|
||||
free();
|
||||
|
||||
switch (interop_buffer.get_type()) {
|
||||
case GraphicsInteropDevice::OPENGL: {
|
||||
const CUresult result = cuGraphicsGLRegisterBuffer(&cu_graphics_resource_,
|
||||
interop_buffer.take_handle(),
|
||||
CU_GRAPHICS_MAP_RESOURCE_FLAGS_NONE);
|
||||
if (result != CUDA_SUCCESS) {
|
||||
LOG_ERROR << "Error registering OpenGL buffer: " << cuewErrorString(result);
|
||||
break;
|
||||
}
|
||||
|
||||
buffer_size_ = interop_buffer.get_size();
|
||||
break;
|
||||
}
|
||||
case GraphicsInteropDevice::VULKAN: {
|
||||
CUDA_EXTERNAL_MEMORY_HANDLE_DESC external_memory_handle_desc = {};
|
||||
# ifdef _WIN32
|
||||
/* cuImportExternalMemory will not take ownership of the handle. */
|
||||
vulkan_windows_handle_ = interop_buffer.take_handle();
|
||||
external_memory_handle_desc.type = CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32;
|
||||
external_memory_handle_desc.handle.win32.handle = reinterpret_cast<void *>(
|
||||
vulkan_windows_handle_);
|
||||
# else
|
||||
/* cuImportExternalMemory will take ownership of the handle. */
|
||||
external_memory_handle_desc.type = CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD;
|
||||
external_memory_handle_desc.handle.fd = interop_buffer.take_handle();
|
||||
# endif
|
||||
external_memory_handle_desc.size = interop_buffer.get_size();
|
||||
|
||||
CUresult result = cuImportExternalMemory(&cu_external_memory_, &external_memory_handle_desc);
|
||||
if (result != CUDA_SUCCESS) {
|
||||
# ifdef _WIN32
|
||||
CloseHandle(HANDLE(vulkan_windows_handle_));
|
||||
vulkan_windows_handle_ = 0;
|
||||
# else
|
||||
close(external_memory_handle_desc.handle.fd);
|
||||
# endif
|
||||
LOG_ERROR << "Error importing Vulkan memory: " << cuewErrorString(result);
|
||||
break;
|
||||
}
|
||||
|
||||
buffer_size_ = interop_buffer.get_size();
|
||||
|
||||
CUDA_EXTERNAL_MEMORY_BUFFER_DESC external_memory_buffer_desc = {};
|
||||
external_memory_buffer_desc.size = external_memory_handle_desc.size;
|
||||
external_memory_buffer_desc.offset = 0;
|
||||
|
||||
CUdeviceptr external_memory_device_ptr = 0;
|
||||
result = cuExternalMemoryGetMappedBuffer(
|
||||
&external_memory_device_ptr, cu_external_memory_, &external_memory_buffer_desc);
|
||||
if (result != CUDA_SUCCESS) {
|
||||
if (external_memory_device_ptr) {
|
||||
cuMemFree(external_memory_device_ptr);
|
||||
external_memory_device_ptr = 0;
|
||||
}
|
||||
|
||||
LOG_ERROR << "Error mapping Vulkan memory: " << cuewErrorString(result);
|
||||
break;
|
||||
}
|
||||
|
||||
cu_external_memory_ptr_ = external_memory_device_ptr;
|
||||
break;
|
||||
}
|
||||
case GraphicsInteropDevice::METAL:
|
||||
case GraphicsInteropDevice::NONE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
device_ptr CUDADeviceGraphicsInterop::map()
|
||||
{
|
||||
CUdeviceptr cu_buffer = 0;
|
||||
|
||||
if (cu_graphics_resource_) {
|
||||
/* OpenGL buffer needs mapping. */
|
||||
CUDAContextScope scope(device_);
|
||||
size_t bytes;
|
||||
|
||||
cuda_device_assert(device_,
|
||||
cuGraphicsMapResources(1, &cu_graphics_resource_, queue_->stream()));
|
||||
cuda_device_assert(
|
||||
device_, cuGraphicsResourceGetMappedPointer(&cu_buffer, &bytes, cu_graphics_resource_));
|
||||
}
|
||||
else {
|
||||
/* Vulkan buffer is always mapped. */
|
||||
cu_buffer = cu_external_memory_ptr_;
|
||||
}
|
||||
|
||||
if (cu_buffer && need_zero_) {
|
||||
cuda_device_assert(device_, cuMemsetD8Async(cu_buffer, 0, buffer_size_, queue_->stream()));
|
||||
|
||||
need_zero_ = false;
|
||||
}
|
||||
|
||||
return static_cast<device_ptr>(cu_buffer);
|
||||
}
|
||||
|
||||
void CUDADeviceGraphicsInterop::unmap()
|
||||
{
|
||||
if (cu_graphics_resource_) {
|
||||
CUDAContextScope scope(device_);
|
||||
|
||||
cuda_device_assert(device_,
|
||||
cuGraphicsUnmapResources(1, &cu_graphics_resource_, queue_->stream()));
|
||||
}
|
||||
}
|
||||
|
||||
void CUDADeviceGraphicsInterop::free()
|
||||
{
|
||||
if (cu_graphics_resource_) {
|
||||
cuda_device_assert(device_, cuGraphicsUnregisterResource(cu_graphics_resource_));
|
||||
cu_graphics_resource_ = nullptr;
|
||||
}
|
||||
|
||||
if (cu_external_memory_ptr_) {
|
||||
cuda_device_assert(device_, cuMemFree(cu_external_memory_ptr_));
|
||||
cu_external_memory_ptr_ = 0;
|
||||
}
|
||||
|
||||
if (cu_external_memory_) {
|
||||
cuda_device_assert(device_, cuDestroyExternalMemory(cu_external_memory_));
|
||||
cu_external_memory_ = nullptr;
|
||||
}
|
||||
|
||||
# ifdef _WIN32
|
||||
if (vulkan_windows_handle_) {
|
||||
CloseHandle(HANDLE(vulkan_windows_handle_));
|
||||
vulkan_windows_handle_ = 0;
|
||||
}
|
||||
# endif
|
||||
|
||||
buffer_size_ = 0;
|
||||
|
||||
need_zero_ = false;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
63
blender-5.2.0/intern/cycles/device/cuda/graphics_interop.h
Normal file
63
blender-5.2.0/intern/cycles/device/cuda/graphics_interop.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#ifdef WITH_CUDA
|
||||
|
||||
# include "device/graphics_interop.h"
|
||||
# include "session/display_driver.h"
|
||||
|
||||
# ifdef WITH_CUDA_DYNLOAD
|
||||
# include "cuew.h"
|
||||
# else
|
||||
# include <cuda.h>
|
||||
# endif
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
class CUDADevice;
|
||||
class CUDADeviceQueue;
|
||||
|
||||
class CUDADeviceGraphicsInterop : public DeviceGraphicsInterop {
|
||||
public:
|
||||
explicit CUDADeviceGraphicsInterop(CUDADeviceQueue *queue);
|
||||
|
||||
CUDADeviceGraphicsInterop(const CUDADeviceGraphicsInterop &other) = delete;
|
||||
CUDADeviceGraphicsInterop(CUDADeviceGraphicsInterop &&other) noexcept = delete;
|
||||
|
||||
~CUDADeviceGraphicsInterop() override;
|
||||
|
||||
CUDADeviceGraphicsInterop &operator=(const CUDADeviceGraphicsInterop &other) = delete;
|
||||
CUDADeviceGraphicsInterop &operator=(CUDADeviceGraphicsInterop &&other) = delete;
|
||||
|
||||
void set_buffer(GraphicsInteropBuffer &interop_buffer) override;
|
||||
|
||||
device_ptr map() override;
|
||||
void unmap() override;
|
||||
|
||||
protected:
|
||||
CUDADeviceQueue *queue_ = nullptr;
|
||||
CUDADevice *device_ = nullptr;
|
||||
|
||||
/* Size of the buffer in bytes. */
|
||||
size_t buffer_size_ = 0;
|
||||
|
||||
/* The destination was requested to be cleared. */
|
||||
bool need_zero_ = false;
|
||||
|
||||
/* CUDA resources. */
|
||||
CUgraphicsResource cu_graphics_resource_ = nullptr;
|
||||
CUexternalMemory cu_external_memory_ = nullptr;
|
||||
CUdeviceptr cu_external_memory_ptr_ = 0;
|
||||
|
||||
/* Vulkan handle to free. */
|
||||
# ifdef _WIN32
|
||||
int64_t vulkan_windows_handle_ = 0;
|
||||
# endif
|
||||
|
||||
void free();
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
56
blender-5.2.0/intern/cycles/device/cuda/kernel.cpp
Normal file
56
blender-5.2.0/intern/cycles/device/cuda/kernel.cpp
Normal file
@@ -0,0 +1,56 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#ifdef WITH_CUDA
|
||||
|
||||
# include "device/cuda/kernel.h"
|
||||
# include "device/cuda/device_impl.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
void CUDADeviceKernels::load(CUDADevice *device)
|
||||
{
|
||||
CUmodule cuModule = device->cuModule;
|
||||
|
||||
for (int i = 0; i < (int)DEVICE_KERNEL_NUM; i++) {
|
||||
CUDADeviceKernel &kernel = kernels_[i];
|
||||
|
||||
if (!device_kernel_has_gpu_function((DeviceKernel)i)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::string function_name = std::string("kernel_gpu_") +
|
||||
device_kernel_as_string((DeviceKernel)i);
|
||||
cuda_device_assert(device,
|
||||
cuModuleGetFunction(&kernel.function, cuModule, function_name.c_str()));
|
||||
|
||||
if (kernel.function) {
|
||||
cuda_device_assert(device, cuFuncSetCacheConfig(kernel.function, CU_FUNC_CACHE_PREFER_L1));
|
||||
|
||||
cuda_device_assert(
|
||||
device,
|
||||
cuOccupancyMaxPotentialBlockSize(
|
||||
&kernel.min_blocks, &kernel.num_threads_per_block, kernel.function, nullptr, 0, 0));
|
||||
}
|
||||
else {
|
||||
LOG_ERROR << "Unable to load kernel " << function_name;
|
||||
}
|
||||
}
|
||||
|
||||
loaded = true;
|
||||
}
|
||||
|
||||
const CUDADeviceKernel &CUDADeviceKernels::get(DeviceKernel kernel) const
|
||||
{
|
||||
return kernels_[(int)kernel];
|
||||
}
|
||||
|
||||
bool CUDADeviceKernels::available(DeviceKernel kernel) const
|
||||
{
|
||||
return kernels_[(int)kernel].function != nullptr;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif /* WITH_CUDA */
|
||||
44
blender-5.2.0/intern/cycles/device/cuda/kernel.h
Normal file
44
blender-5.2.0/intern/cycles/device/cuda/kernel.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef WITH_CUDA
|
||||
|
||||
# include "device/kernel.h"
|
||||
|
||||
# ifdef WITH_CUDA_DYNLOAD
|
||||
# include "cuew.h"
|
||||
# else
|
||||
# include <cuda.h>
|
||||
# endif
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
class CUDADevice;
|
||||
|
||||
/* CUDA kernel and associate occupancy information. */
|
||||
class CUDADeviceKernel {
|
||||
public:
|
||||
CUfunction function = nullptr;
|
||||
|
||||
int num_threads_per_block = 0;
|
||||
int min_blocks = 0;
|
||||
};
|
||||
|
||||
/* Cache of CUDA kernels for each DeviceKernel. */
|
||||
class CUDADeviceKernels {
|
||||
public:
|
||||
void load(CUDADevice *device);
|
||||
const CUDADeviceKernel &get(DeviceKernel kernel) const;
|
||||
bool available(DeviceKernel kernel) const;
|
||||
|
||||
protected:
|
||||
CUDADeviceKernel kernels_[DEVICE_KERNEL_NUM];
|
||||
bool loaded = false;
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif /* WITH_CUDA */
|
||||
271
blender-5.2.0/intern/cycles/device/cuda/queue.cpp
Normal file
271
blender-5.2.0/intern/cycles/device/cuda/queue.cpp
Normal file
@@ -0,0 +1,271 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#ifdef WITH_CUDA
|
||||
|
||||
# include "device/cuda/queue.h"
|
||||
|
||||
# include "device/cuda/device_impl.h"
|
||||
# include "device/cuda/graphics_interop.h"
|
||||
# include "device/cuda/kernel.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* CUDADeviceQueue */
|
||||
|
||||
CUDADeviceQueue::CUDADeviceQueue(CUDADevice *device)
|
||||
: DeviceQueue(device), cuda_device_(device), cuda_stream_(nullptr)
|
||||
{
|
||||
const CUDAContextScope scope(cuda_device_);
|
||||
cuda_device_assert(cuda_device_, cuStreamCreate(&cuda_stream_, CU_STREAM_NON_BLOCKING));
|
||||
}
|
||||
|
||||
CUDADeviceQueue::~CUDADeviceQueue()
|
||||
{
|
||||
const CUDAContextScope scope(cuda_device_);
|
||||
cuStreamDestroy(cuda_stream_);
|
||||
}
|
||||
|
||||
int CUDADeviceQueue::num_concurrent_states(const size_t state_size) const
|
||||
{
|
||||
const int max_num_threads = cuda_device_->get_num_multiprocessors() *
|
||||
cuda_device_->get_max_num_threads_per_multiprocessor();
|
||||
int num_states = max(max_num_threads, 65536) * 16;
|
||||
|
||||
const char *factor_str = getenv("CYCLES_CONCURRENT_STATES_FACTOR");
|
||||
if (factor_str) {
|
||||
const float factor = (float)atof(factor_str);
|
||||
if (factor != 0.0f) {
|
||||
num_states = max((int)(num_states * factor), 1024);
|
||||
}
|
||||
else {
|
||||
LOG_TRACE << "CYCLES_CONCURRENT_STATES_FACTOR evaluated to 0";
|
||||
}
|
||||
}
|
||||
|
||||
LOG_TRACE << "GPU queue concurrent states: " << num_states << ", using up to "
|
||||
<< string_human_readable_size(num_states * state_size);
|
||||
|
||||
return num_states;
|
||||
}
|
||||
|
||||
int CUDADeviceQueue::num_concurrent_busy_states(const size_t /*state_size*/) const
|
||||
{
|
||||
const int max_num_threads = cuda_device_->get_num_multiprocessors() *
|
||||
cuda_device_->get_max_num_threads_per_multiprocessor();
|
||||
|
||||
if (max_num_threads == 0) {
|
||||
return 65536;
|
||||
}
|
||||
|
||||
return 4 * max_num_threads;
|
||||
}
|
||||
|
||||
void CUDADeviceQueue::init_execution()
|
||||
{
|
||||
/* Synchronize all textures and memory copies before executing task.
|
||||
* Use default stream (nullptr) since that's what we will synchronize
|
||||
* here to ensure all scene data is copied. */
|
||||
CUDAContextScope scope(cuda_device_);
|
||||
cuda_device_->load_image_info(nullptr);
|
||||
cuda_device_assert(cuda_device_, cuCtxSynchronize());
|
||||
|
||||
debug_init_execution();
|
||||
}
|
||||
|
||||
void CUDADeviceQueue::load_image_info()
|
||||
{
|
||||
CUDAContextScope scope(cuda_device_);
|
||||
cuda_device_->load_image_info(this);
|
||||
}
|
||||
|
||||
bool CUDADeviceQueue::enqueue(DeviceKernel kernel,
|
||||
const int work_size,
|
||||
const DeviceKernelArguments &args)
|
||||
{
|
||||
if (cuda_device_->have_error()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
debug_enqueue_begin(kernel, work_size);
|
||||
|
||||
const CUDAContextScope scope(cuda_device_);
|
||||
|
||||
/* Update image info in case integrator memory alloc caused texture to move to host. */
|
||||
if (cuda_device_->load_image_info(nullptr)) {
|
||||
cuda_device_assert(cuda_device_, cuCtxSynchronize());
|
||||
if (cuda_device_->have_error()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Compute kernel launch parameters. */
|
||||
const CUDADeviceKernel &cuda_kernel = cuda_device_->kernels.get(kernel);
|
||||
const int num_threads_per_block = cuda_kernel.num_threads_per_block;
|
||||
const int num_blocks = divide_up(work_size, num_threads_per_block);
|
||||
|
||||
int shared_mem_bytes = 0;
|
||||
|
||||
switch (kernel) {
|
||||
case DEVICE_KERNEL_INTEGRATOR_QUEUED_PATHS_ARRAY:
|
||||
case DEVICE_KERNEL_INTEGRATOR_QUEUED_SHADOW_PATHS_ARRAY:
|
||||
case DEVICE_KERNEL_INTEGRATOR_ACTIVE_PATHS_ARRAY:
|
||||
case DEVICE_KERNEL_INTEGRATOR_TERMINATED_PATHS_ARRAY:
|
||||
case DEVICE_KERNEL_INTEGRATOR_SORTED_PATHS_ARRAY:
|
||||
case DEVICE_KERNEL_INTEGRATOR_COMPACT_PATHS_ARRAY:
|
||||
case DEVICE_KERNEL_INTEGRATOR_TERMINATED_SHADOW_PATHS_ARRAY:
|
||||
case DEVICE_KERNEL_INTEGRATOR_COMPACT_SHADOW_PATHS_ARRAY:
|
||||
/* See parall_active_index.h for why this amount of shared memory is needed. */
|
||||
shared_mem_bytes = (num_threads_per_block + 1) * sizeof(int);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Launch kernel. */
|
||||
assert_success(cuLaunchKernel(cuda_kernel.function,
|
||||
num_blocks,
|
||||
1,
|
||||
1,
|
||||
num_threads_per_block,
|
||||
1,
|
||||
1,
|
||||
shared_mem_bytes,
|
||||
cuda_stream_,
|
||||
const_cast<void **>(args.values),
|
||||
nullptr),
|
||||
"enqueue");
|
||||
|
||||
debug_enqueue_end();
|
||||
|
||||
return !(cuda_device_->have_error());
|
||||
}
|
||||
|
||||
bool CUDADeviceQueue::synchronize()
|
||||
{
|
||||
if (cuda_device_->have_error()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const CUDAContextScope scope(cuda_device_);
|
||||
assert_success(cuStreamSynchronize(cuda_stream_), "synchronize");
|
||||
|
||||
debug_synchronize();
|
||||
|
||||
return !(cuda_device_->have_error());
|
||||
}
|
||||
|
||||
void CUDADeviceQueue::zero_to_device(device_memory &mem)
|
||||
{
|
||||
assert(mem.type != MEM_IMAGE_TEXTURE);
|
||||
|
||||
if (mem.memory_size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Allocate on demand. */
|
||||
if (mem.device_pointer == 0) {
|
||||
if (mem.type == MEM_GLOBAL) {
|
||||
cuda_device_->global_alloc(mem);
|
||||
}
|
||||
else {
|
||||
cuda_device_->mem_alloc(mem);
|
||||
}
|
||||
}
|
||||
|
||||
/* Zero memory on device. */
|
||||
device_ptr d_ptr = mem.device->mem_device_ptr(mem, cuda_device_);
|
||||
assert(d_ptr != 0);
|
||||
|
||||
const CUDAContextScope scope(cuda_device_);
|
||||
assert_success(cuMemsetD8Async((CUdeviceptr)d_ptr, 0, mem.memory_size(), cuda_stream_),
|
||||
"zero_to_device");
|
||||
}
|
||||
|
||||
void CUDADeviceQueue::copy_to_device(device_memory &mem)
|
||||
{
|
||||
assert(mem.type != MEM_IMAGE_TEXTURE);
|
||||
|
||||
if (mem.memory_size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Allocate on demand. */
|
||||
if (mem.device_pointer == 0) {
|
||||
if (mem.type == MEM_GLOBAL) {
|
||||
cuda_device_->global_alloc(mem);
|
||||
}
|
||||
else {
|
||||
cuda_device_->mem_alloc(mem);
|
||||
}
|
||||
}
|
||||
|
||||
device_ptr d_ptr = mem.device->mem_device_ptr(mem, cuda_device_);
|
||||
assert(d_ptr != 0);
|
||||
assert(mem.host_pointer != nullptr);
|
||||
|
||||
/* Copy memory to device. */
|
||||
const CUDAContextScope scope(cuda_device_);
|
||||
assert_success(
|
||||
cuMemcpyHtoDAsync((CUdeviceptr)d_ptr, mem.host_pointer, mem.memory_size(), cuda_stream_),
|
||||
"copy_to_device");
|
||||
}
|
||||
|
||||
void CUDADeviceQueue::copy_from_device(device_memory &mem)
|
||||
{
|
||||
assert(mem.type != MEM_GLOBAL && mem.type != MEM_IMAGE_TEXTURE);
|
||||
|
||||
if (mem.memory_size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert(mem.device_pointer != 0);
|
||||
assert(mem.host_pointer != nullptr);
|
||||
|
||||
/* Copy memory from device. */
|
||||
const CUDAContextScope scope(cuda_device_);
|
||||
assert_success(
|
||||
cuMemcpyDtoHAsync(
|
||||
mem.host_pointer, (CUdeviceptr)mem.device_pointer, mem.memory_size(), cuda_stream_),
|
||||
"copy_from_device");
|
||||
}
|
||||
|
||||
void *CUDADeviceQueue::copy_from_device_synchronized(device_memory &mem, vector<uint8_t> &storage)
|
||||
{
|
||||
if (mem.memory_size() == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
storage.resize(mem.memory_size());
|
||||
|
||||
device_ptr d_ptr = mem.device->mem_device_ptr(mem, cuda_device_);
|
||||
assert(d_ptr != 0);
|
||||
|
||||
const CUDAContextScope scope(cuda_device_);
|
||||
assert_success(
|
||||
cuMemcpyDtoHAsync(storage.data(), (CUdeviceptr)d_ptr, mem.memory_size(), cuda_stream_),
|
||||
"copy_from_device_synchronized");
|
||||
|
||||
synchronize();
|
||||
return storage.data();
|
||||
}
|
||||
|
||||
void CUDADeviceQueue::assert_success(CUresult result, const char *operation)
|
||||
{
|
||||
if (result != CUDA_SUCCESS) {
|
||||
const char *name = cuewErrorString(result);
|
||||
cuda_device_->set_error(string_printf(
|
||||
"%s in CUDA queue %s (%s)", name, operation, debug_active_kernels().c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
unique_ptr<DeviceGraphicsInterop> CUDADeviceQueue::graphics_interop_create()
|
||||
{
|
||||
return make_unique<CUDADeviceGraphicsInterop>(this);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif /* WITH_CUDA */
|
||||
58
blender-5.2.0/intern/cycles/device/cuda/queue.h
Normal file
58
blender-5.2.0/intern/cycles/device/cuda/queue.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef WITH_CUDA
|
||||
|
||||
# include "device/memory.h"
|
||||
# include "device/queue.h"
|
||||
|
||||
# include "device/cuda/util.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
class CUDADevice;
|
||||
class device_memory;
|
||||
|
||||
/* Base class for CUDA queues. */
|
||||
class CUDADeviceQueue : public DeviceQueue {
|
||||
public:
|
||||
CUDADeviceQueue(CUDADevice *device);
|
||||
~CUDADeviceQueue() override;
|
||||
|
||||
int num_concurrent_states(const size_t state_size) const override;
|
||||
int num_concurrent_busy_states(const size_t state_size) const override;
|
||||
|
||||
void init_execution() override;
|
||||
void load_image_info() override;
|
||||
|
||||
bool enqueue(DeviceKernel kernel,
|
||||
const int work_size,
|
||||
const DeviceKernelArguments &args) override;
|
||||
|
||||
bool synchronize() override;
|
||||
|
||||
void zero_to_device(device_memory &mem) override;
|
||||
void copy_to_device(device_memory &mem) override;
|
||||
void copy_from_device(device_memory &mem) override;
|
||||
void *copy_from_device_synchronized(device_memory &mem, vector<uint8_t> &storage) override;
|
||||
|
||||
virtual CUstream stream()
|
||||
{
|
||||
return cuda_stream_;
|
||||
}
|
||||
|
||||
unique_ptr<DeviceGraphicsInterop> graphics_interop_create() override;
|
||||
|
||||
protected:
|
||||
CUDADevice *cuda_device_;
|
||||
CUstream cuda_stream_;
|
||||
|
||||
void assert_success(CUresult result, const char *operation);
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif /* WITH_CUDA */
|
||||
49
blender-5.2.0/intern/cycles/device/cuda/util.cpp
Normal file
49
blender-5.2.0/intern/cycles/device/cuda/util.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#ifdef WITH_CUDA
|
||||
|
||||
# include "device/cuda/util.h"
|
||||
# include "device/cuda/device_impl.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
CUDAContextScope::CUDAContextScope(CUDADevice *device) : device(device)
|
||||
{
|
||||
cuda_device_assert(device, cuCtxPushCurrent(device->cuContext));
|
||||
}
|
||||
|
||||
CUDAContextScope::~CUDAContextScope()
|
||||
{
|
||||
cuda_device_assert(device, cuCtxPopCurrent(nullptr));
|
||||
}
|
||||
|
||||
# ifndef WITH_CUDA_DYNLOAD
|
||||
const char *cuewErrorString(CUresult result)
|
||||
{
|
||||
/* We can only give error code here without major code duplication, that
|
||||
* should be enough since dynamic loading is only being disabled by folks
|
||||
* who knows what they're doing anyway.
|
||||
*
|
||||
* NOTE: Avoid call from several threads.
|
||||
*/
|
||||
static string error;
|
||||
error = string_printf("%d", result);
|
||||
return error.c_str();
|
||||
}
|
||||
|
||||
const char *cuewCompilerPath()
|
||||
{
|
||||
return CYCLES_CUDA_NVCC_EXECUTABLE;
|
||||
}
|
||||
|
||||
int cuewCompilerVersion()
|
||||
{
|
||||
return (CUDA_VERSION / 100) + (CUDA_VERSION % 100 / 10);
|
||||
}
|
||||
# endif
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif /* WITH_CUDA */
|
||||
63
blender-5.2.0/intern/cycles/device/cuda/util.h
Normal file
63
blender-5.2.0/intern/cycles/device/cuda/util.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef WITH_CUDA
|
||||
|
||||
# ifdef WITH_CUDA_DYNLOAD
|
||||
# include <cuew.h>
|
||||
# else
|
||||
# include <cuda.h>
|
||||
# endif
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
class CUDADevice;
|
||||
|
||||
/* Utility to push/pop CUDA context. */
|
||||
class CUDAContextScope {
|
||||
public:
|
||||
CUDAContextScope(CUDADevice *device);
|
||||
~CUDAContextScope();
|
||||
|
||||
private:
|
||||
CUDADevice *device;
|
||||
};
|
||||
|
||||
/* Utility for checking return values of CUDA function calls. */
|
||||
# define cuda_device_assert(cuda_device, stmt) \
|
||||
{ \
|
||||
CUresult result = stmt; \
|
||||
if (result != CUDA_SUCCESS) { \
|
||||
const char *name = cuewErrorString(result); \
|
||||
cuda_device->set_error( \
|
||||
string_printf("%s in %s (%s:%d)", name, #stmt, __FILE__, __LINE__)); \
|
||||
} \
|
||||
} \
|
||||
(void)0
|
||||
|
||||
# define cuda_assert(stmt) cuda_device_assert(this, stmt)
|
||||
|
||||
# ifndef WITH_CUDA_DYNLOAD
|
||||
/* Transparently implement some functions, so majority of the file does not need
|
||||
* to worry about difference between dynamically loaded and linked CUDA at all. */
|
||||
const char *cuewErrorString(CUresult result);
|
||||
const char *cuewCompilerPath();
|
||||
int cuewCompilerVersion();
|
||||
# endif /* WITH_CUDA_DYNLOAD */
|
||||
|
||||
static inline bool cudaSupportsDevice(const int cudaDevID)
|
||||
{
|
||||
int major;
|
||||
cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, cudaDevID);
|
||||
if (major >= 5) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif /* WITH_CUDA */
|
||||
Reference in New Issue
Block a user