Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 22 additions & 9 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ project(FunGT)
# ════════════════════════════════════════════════════════════════════════════
option(FUNGT_USE_CUDA "Enable CUDA backend for NVIDIA GPUs" ON)
option(FUNGT_USE_SYCL "Enable SYCL backend for Intel GPUs" ON)
set(SYCL_CUDA_ARCH sm_75 CACHE STRING "NVIDIA GPU architecture for SYCL CUDA backend")
set_property(CACHE SYCL_CUDA_ARCH PROPERTY STRINGS sm_50 sm_52 sm_53 sm_60 sm_61 sm_62 sm_70 sm_72 sm_75 sm_80 sm_86 sm_87 sm_89 sm_90)
option(FUNGT_USE_OPENCL "Enable OpenCL backend" ON)
set(FUNGT_CUDA_ARCH 89 CACHE STRING "NVIDIA GPU compute capability")
set_property(CACHE FUNGT_CUDA_ARCH PROPERTY STRINGS 50 52 53 60 61 62 70 72 75 80 86 87 89 90)
set(SYCL_CUDA_ARCH "sm_${FUNGT_CUDA_ARCH}")

# Allow FUNGT_BASE_DIR to be set externally (command line, environment, or cache)
# Priority: 1. Cache variable, 2. Environment variable, 3. Default fallback
Expand Down Expand Up @@ -145,6 +147,15 @@ if(UNIX)
set(PBR_SYCL_LIB pbr_sycl)
message(STATUS "PBR SYCL renderer library: ${PBR_LIB_DIR}/libpbr_sycl.a")
endif()

if(FUNGT_USE_OPENCL)
add_library(pbr_opencl STATIC IMPORTED)
set_target_properties(pbr_opencl PROPERTIES
IMPORTED_LOCATION "${PBR_LIB_DIR}/libpbr_opencl.a"
)
set(PBR_OPENCL_LIB pbr_opencl)
message(STATUS "PBR OpenCL renderer library: ${PBR_LIB_DIR}/libpbr_opencl.a")
endif()
endif()

if (WIN32)
Expand Down Expand Up @@ -372,7 +383,7 @@ if(FUNGT_USE_CUDA)
set_target_properties(FunGT PROPERTIES
CUDA_RESOLVE_DEVICE_SYMBOLS ON
CUDA_SEPARABLE_COMPILATION ON
CUDA_ARCHITECTURES "native"
CUDA_ARCHITECTURES ${FUNGT_CUDA_ARCH}
)
endif()
# ════════════════════════════════════════════════════════════════════════════
Expand Down Expand Up @@ -491,11 +502,12 @@ elseif (UNIX)
dl
funlib
imgui
${OpenCL_LIBRARIES}
${CUDA_BACKEND_LIB}
pbr_core
${PBR_CUDA_LIB}
${PBR_SYCL_LIB}
${PBR_OPENCL_LIB}
${OpenCL_LIBRARIES}
$<$<BOOL:${FUNGT_USE_CUDA}>:CUDA::cudart_static>
$<$<BOOL:${FUNGT_USE_CUDA}>:CUDA::cuda_driver>
)
Expand Down Expand Up @@ -533,6 +545,9 @@ elseif (UNIX)
if(FUNGT_USE_SYCL)
target_compile_definitions(FunGT PRIVATE FUNGT_USE_SYCL)
endif()
if(FUNGT_USE_OPENCL)
target_compile_definitions(FunGT PRIVATE FUNGT_USE_OPENCL)
endif()

endif()

Expand All @@ -543,12 +558,10 @@ message(STATUS "")
message(STATUS "════════════════════════════════════════")
message(STATUS " FunGT Build Configuration")
message(STATUS "════════════════════════════════════════")
message(STATUS " Main Compiler: ${CMAKE_CXX_COMPILER}")
message(STATUS " Main Compiler: Intel DPC++")
message(STATUS " CUDA Backend: ${FUNGT_USE_CUDA}")
message(STATUS " SYCL Backend: ${FUNGT_USE_SYCL}")
message(STATUS " OpenCL Backend: ${FUNGT_USE_OPENCL}")
message(STATUS " Build Type: ${CMAKE_BUILD_TYPE}")
if(FUNGT_USE_CUDA)
message(STATUS " CUDA Compiled: Separately with g++")
endif()
message(STATUS "════════════════════════════════════════")
message(STATUS "")
message(STATUS "")
29 changes: 18 additions & 11 deletions GUI/lights_editor_window.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ class LightEditorWindow : public ImGuiWindow {
if (m_selectedIndex >= 0 && m_selectedIndex < (int)lights.size()) {
if (ImGui::Button("Remove Selected")) {
lights.erase(lights.begin() + m_selectedIndex);
m_sceneManager->markRaySpaceDirty(SceneManager::RaySpaceDirtyLights);
m_selectedIndex = -1;
ImGui::End();
return;
Expand Down Expand Up @@ -106,15 +107,17 @@ class LightEditorWindow : public ImGuiWindow {
ImGui::Spacing();
ImGui::Separator();

bool lightChanged = false;

// Common properties
ImGui::Text("Position");
ImGui::DragFloat3("##Pos", &light.position.x, 0.1f);
lightChanged |= ImGui::DragFloat3("##Pos", &light.position.x, 0.1f);

ImGui::Text("Color");
ImGui::ColorEdit3("##Color", &light.color.x, ImGuiColorEditFlags_Float);
lightChanged |= ImGui::ColorEdit3("##Color", &light.color.x, ImGuiColorEditFlags_Float);

ImGui::Text("Power");
ImGui::DragFloat("##Power", &light.power, 0.1f, 0.0f, 10000.f);
lightChanged |= ImGui::DragFloat("##Power", &light.power, 0.1f, 0.0f, 10000.f);

ImGui::Spacing();
ImGui::Separator();
Expand All @@ -124,33 +127,37 @@ class LightEditorWindow : public ImGuiWindow {
{
case SceneLightType::Point:
ImGui::Text("Radius");
ImGui::DragFloat("##Radius", &light.radius, 0.01f, 0.0f, 100.f);
lightChanged |= ImGui::DragFloat("##Radius", &light.radius, 0.01f, 0.0f, 100.f);
break;

case SceneLightType::Sun:
ImGui::Text("Direction");
ImGui::DragFloat3("##Dir", &light.direction.x, 0.01f, -1.f, 1.f);
lightChanged |= ImGui::DragFloat3("##Dir", &light.direction.x, 0.01f, -1.f, 1.f);
break;

case SceneLightType::Spot:
ImGui::Text("Direction");
ImGui::DragFloat3("##SpotDir", &light.direction.x, 0.01f, -1.f, 1.f);
lightChanged |= ImGui::DragFloat3("##SpotDir", &light.direction.x, 0.01f, -1.f, 1.f);
ImGui::Text("Inner Angle");
ImGui::DragFloat("##Inner", &light.innerAngle, 0.5f, 0.f, light.outerAngle);
lightChanged |= ImGui::DragFloat("##Inner", &light.innerAngle, 0.5f, 0.f, light.outerAngle);
ImGui::Text("Outer Angle");
ImGui::DragFloat("##Outer", &light.outerAngle, 0.5f, light.innerAngle, 90.f);
lightChanged |= ImGui::DragFloat("##Outer", &light.outerAngle, 0.5f, light.innerAngle, 90.f);
break;

case SceneLightType::Area:
ImGui::Text("Normal");
ImGui::DragFloat3("##Normal", &light.normal.x, 0.01f, -1.f, 1.f);
lightChanged |= ImGui::DragFloat3("##Normal", &light.normal.x, 0.01f, -1.f, 1.f);
ImGui::Text("Size");
ImGui::DragFloat2("##Size", &light.size.x, 0.1f, 0.1f, 100.f);
lightChanged |= ImGui::DragFloat2("##Size", &light.size.x, 0.1f, 0.1f, 100.f);
break;
}

if (lightChanged) {
m_sceneManager->markRaySpaceDirty(SceneManager::RaySpaceDirtyLights);
}

ImGui::End();
}
};

#endif // _LIGHT_EDITOR_WINDOW_H_
#endif // _LIGHT_EDITOR_WINDOW_H_
17 changes: 12 additions & 5 deletions GUI/material_editor_window.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,35 +131,42 @@ class MaterialEditorWindow : public ImGuiWindow {
ImGui::Separator();
ImGui::Spacing();

bool materialChanged = false;

ImGui::Text("Base Color");
ImGui::ColorEdit3("##BaseColor", &mat.m_baseColor.x, ImGuiColorEditFlags_Float);
materialChanged |= ImGui::ColorEdit3("##BaseColor", &mat.m_baseColor.x, ImGuiColorEditFlags_Float);

ImGui::Spacing();
ImGui::Separator();
ImGui::Spacing();

ImGui::Text("Metallic");
ImGui::SliderFloat("##Metallic", &mat.m_metallic, 0.0f, 1.0f, "%.3f");
materialChanged |= ImGui::SliderFloat("##Metallic", &mat.m_metallic, 0.0f, 1.0f, "%.3f");

ImGui::Text("Roughness");
ImGui::SliderFloat("##Roughness", &mat.m_roughness, 0.05f, 1.0f, "%.3f");
materialChanged |= ImGui::SliderFloat("##Roughness", &mat.m_roughness, 0.05f, 1.0f, "%.3f");

ImGui::Text("Reflectance");
ImGui::SliderFloat("##Reflectance", &mat.m_reflectance, 0.0f, 1.0f, "%.3f");
materialChanged |= ImGui::SliderFloat("##Reflectance", &mat.m_reflectance, 0.0f, 1.0f, "%.3f");

ImGui::Spacing();
ImGui::Separator();
ImGui::Spacing();
// Emission
ImGui::Text("Emission");
ImGui::SliderFloat("##Emission", &mat.m_emission, 0.0f, 50.0f, "%.1f");
materialChanged |= ImGui::SliderFloat("##Emission", &mat.m_emission, 0.0f, 50.0f, "%.1f");

ImGui::Spacing();
ImGui::Separator();
ImGui::Spacing();
// Reset button
if (ImGui::Button("Reset to Default", ImVec2(-1, 0))) {
mat = Material::createDefaultMaterial();
materialChanged = true;
}

if (materialChanged) {
m_sceneManager->markRaySpaceDirty(SceneManager::RaySpaceDirtyShading);
}

// Info section
Expand Down
70 changes: 46 additions & 24 deletions GUI/render_action_window.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,27 @@ void RenderWindow::onImGuiRender() {
// VIEWPORT PREVIEW
ImGui::SeparatorText("Viewport Preview");

#ifdef FUNGT_USE_OPENCL
if (ImGui::Checkbox("Use OpenCL Interop", &m_useOpenCLPreview)) {
if (m_viewportPathTrace && m_viewport) {
if (m_useOpenCLPreview) {
ComputeRender::SetBackend(Compute::Backend::OPENCL);
} else {
selectComputeBackend();
}
m_viewport->enablePathTracing(true);
m_viewport->resetAccumulation();
}
}
#endif

if (ImGui::Checkbox("Enable RaySpace Preview", &m_viewportPathTrace)) {
if (m_viewport) {
if (m_useOpenCLPreview) {
ComputeRender::SetBackend(Compute::Backend::OPENCL);
} else {
selectComputeBackend();
}
m_viewport->enablePathTracing(m_viewportPathTrace);
if (m_viewportPathTrace) {
m_viewport->resetAccumulation();
Expand Down Expand Up @@ -158,29 +177,7 @@ void RenderWindow::triggerRender() {
m_isRendering = true;

try {
// SET COMPUTE BACKEND FROM SELECTED DEVICE
{
const auto& devices = m_gpuManager->getDevices();
int activeIdx = m_gpuManager->getActiveDeviceIndex();
if (activeIdx >= 0 && activeIdx < static_cast<int>(devices.size())) {
const auto& dev = devices[activeIdx];
if (dev.backend == fungt::GPUBackend::CUDA) {
ComputeRender::SetBackend(Compute::Backend::CUDA);
}
else if (dev.backend == fungt::GPUBackend::SYCL) {
bool isNvidia = dev.vendor.find("NVIDIA") != std::string::npos ||
dev.vendor.find("nvidia") != std::string::npos;
ComputeRender::SetBackend(isNvidia ? Compute::Backend::SYCL_CUDA
: Compute::Backend::SYCL);
}
else {
ComputeRender::SetBackend(Compute::Backend::CPU);
}
}
else {
ComputeRender::SetBackend(Compute::Backend::CUDA);
}
}
selectComputeBackend();
std::cout << "Backend: " << ComputeRender::GetBackendName() << std::endl;

// SYNC CAMERA FROM VIEWPORT
Expand Down Expand Up @@ -268,4 +265,29 @@ void RenderWindow::triggerRender() {
}

m_isRendering = false;
}
}

void RenderWindow::selectComputeBackend()
{
const auto& devices = m_gpuManager->getDevices();
const int activeIdx = m_gpuManager->getActiveDeviceIndex();
if (activeIdx < 0 || activeIdx >= static_cast<int>(devices.size())) {
ComputeRender::SetBackend(Compute::Backend::CPU);
return;
}

const auto& device = devices[activeIdx];
if (device.backend == fungt::GPUBackend::CUDA) {
ComputeRender::SetBackend(Compute::Backend::CUDA);
} else if (device.backend == fungt::GPUBackend::SYCL) {
const bool isNvidia =
device.vendor.find("NVIDIA") != std::string::npos ||
device.vendor.find("nvidia") != std::string::npos;
ComputeRender::SetBackend(
isNvidia ? Compute::Backend::SYCL_CUDA : Compute::Backend::SYCL);
} else if (device.backend == fungt::GPUBackend::OPENCL) {
ComputeRender::SetBackend(Compute::Backend::OPENCL);
} else {
ComputeRender::SetBackend(Compute::Backend::CPU);
}
}
8 changes: 7 additions & 1 deletion GUI/render_action_window.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ class RenderWindow : public ImGuiWindow {
bool m_useViewportSize = false;
bool m_isRendering = false;
bool m_viewportPathTrace = false;
#ifdef FUNGT_USE_OPENCL
bool m_useOpenCLPreview = true;
#else
bool m_useOpenCLPreview = false;
#endif
int m_previewSamples = 32;
ViewPort* m_viewport = nullptr;

Expand All @@ -39,6 +44,7 @@ class RenderWindow : public ImGuiWindow {
int m_viewportHeight = 1080;

void triggerRender();
void selectComputeBackend();

public:
RenderWindow(std::shared_ptr<SceneManager> sceneManager, Camera* camera, ViewPort* viewport,
Expand All @@ -58,4 +64,4 @@ class RenderWindow : public ImGuiWindow {
void onImGuiRender() override;
};

#endif // _RENDER_WINDOW_H_
#endif // _RENDER_WINDOW_H_
4 changes: 3 additions & 1 deletion GUI/render_settings_window.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ class RenderSettingsWindow : public ImGuiWindow {
ImGui::Spacing();
renderBackendSection("SYCL Devices", fungt::GPUBackend::SYCL);
ImGui::Spacing();
renderBackendSection("OpenCL Devices", fungt::GPUBackend::OPENCL);
ImGui::Spacing();
renderBackendSection("OpenGL Fallback", fungt::GPUBackend::OPENGL);
}
}
Expand Down Expand Up @@ -116,4 +118,4 @@ class RenderSettingsWindow : public ImGuiWindow {
}
};

#endif // _RENDER_SETTINGS_WINDOW_H_
#endif // _RENDER_SETTINGS_WINDOW_H_
44 changes: 43 additions & 1 deletion InfoDevice/gpu_device_info.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#include "gpu_device_info.hpp"
#include <iostream>
#ifdef FUNGT_USE_OPENCL
#include <CL/cl.h>
#endif

// ════════════════════════════════════════════════════════════════════════════
// GPU Device Manager Implementation
Expand Down Expand Up @@ -59,6 +62,45 @@ void GPUDeviceManager::initialize() {
std::cout << " SYCL backend disabled (compile with -DFUNGT_USE_SYCL=ON)" << std::endl;
#endif

// Find OpenCL GPU devices.
#ifdef FUNGT_USE_OPENCL
cl_uint platformCount = 0;
if (clGetPlatformIDs(0, nullptr, &platformCount) == CL_SUCCESS) {
std::vector<cl_platform_id> platforms(platformCount);
clGetPlatformIDs(platformCount, platforms.data(), nullptr);

for (cl_platform_id platform : platforms) {
cl_uint deviceCount = 0;
if (clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 0, nullptr, &deviceCount) != CL_SUCCESS) {
continue;
}

std::vector<cl_device_id> devices(deviceCount);
clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, deviceCount, devices.data(), nullptr);
for (cl_uint i = 0; i < deviceCount; ++i) {
char name[256] = {};
char vendor[256] = {};
cl_ulong memory = 0;
cl_uint computeUnits = 0;
clGetDeviceInfo(devices[i], CL_DEVICE_NAME, sizeof(name), name, nullptr);
clGetDeviceInfo(devices[i], CL_DEVICE_VENDOR, sizeof(vendor), vendor, nullptr);
clGetDeviceInfo(devices[i], CL_DEVICE_GLOBAL_MEM_SIZE, sizeof(memory), &memory, nullptr);
clGetDeviceInfo(devices[i], CL_DEVICE_MAX_COMPUTE_UNITS, sizeof(computeUnits), &computeUnits, nullptr);

fungt::GPUDeviceInfo info;
info.id = static_cast<int>(i);
info.name = name;
info.vendor = vendor;
info.memory_bytes = static_cast<size_t>(memory);
info.compute_units = static_cast<int>(computeUnits);
info.backend = fungt::GPUBackend::OPENCL;
info.isActive = false;
all_devices_.push_back(std::move(info));
}
}
}
#endif

// Add OpenGL fallback device (always available)
fungt::GPUDeviceInfo opengl_device;
opengl_device.id = static_cast<int>(all_devices_.size());
Expand Down Expand Up @@ -106,4 +148,4 @@ void GPUDeviceManager::setActiveDevice(int deviceIndex) {

int GPUDeviceManager::getActiveDeviceIndex() const {
return active_device_index_;
}
}
Loading