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
44 changes: 43 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,17 @@ endif()

target_include_directories(${HIPRT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_include_directories(${HIPRT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/contrib/Orochi)
target_include_directories(${HIPRT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/contrib/embree/include)

if(WIN32)
target_link_directories(${HIPRT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/contrib/embree/win)
target_link_libraries(${HIPRT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/contrib/embree/win/embree4.lib)
endif()

if(UNIX)
target_link_directories(${HIPRT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/contrib/embree/linux)
target_link_libraries(${HIPRT_NAME} embree4 tbb)
endif()

file(GLOB_RECURSE hiprt_sources "${CMAKE_CURRENT_SOURCE_DIR}/hiprt/*.h" "${CMAKE_CURRENT_SOURCE_DIR}/hiprt/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/hiprt/*.inl")
list(FILTER hiprt_sources EXCLUDE REGEX "hiprt/bitcodes/.*")
Expand Down Expand Up @@ -664,7 +675,18 @@ if(NOT NO_UNITTEST)
target_link_libraries(unittest PRIVATE pthread dl)
endif()

file(GLOB_RECURSE unittest_sources "${CMAKE_CURRENT_SOURCE_DIR}/test/hiprtT*.h" "${CMAKE_CURRENT_SOURCE_DIR}/test/hiprtT*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/test/shared.h" "${CMAKE_CURRENT_SOURCE_DIR}/test/main.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/test/CornellBox.h" "${CMAKE_CURRENT_SOURCE_DIR}/test/kernels/*.h" "${CMAKE_CURRENT_SOURCE_DIR}/contrib/gtest-1.6.0/gtest-all.cc")
file(GLOB_RECURSE unittest_sources
"${CMAKE_CURRENT_SOURCE_DIR}/test/hiprtT*.h"
"${CMAKE_CURRENT_SOURCE_DIR}/test/hiprtT*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/test/Cpu*Test.h"
"${CMAKE_CURRENT_SOURCE_DIR}/test/Cpu*Test.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/test/Hybrid*Test.h"
"${CMAKE_CURRENT_SOURCE_DIR}/test/Hybrid*Test.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/test/shared.h"
"${CMAKE_CURRENT_SOURCE_DIR}/test/main.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/test/CornellBox.h"
"${CMAKE_CURRENT_SOURCE_DIR}/test/kernels/*.h"
"${CMAKE_CURRENT_SOURCE_DIR}/contrib/gtest-1.6.0/gtest-all.cc")


target_sources(unittest PRIVATE ${unittest_sources} ${orochi_sources})
Expand Down Expand Up @@ -720,3 +742,23 @@ if(HIPRTEW)

target_compile_definitions(hiprtewtest PRIVATE GTEST_HAS_TR1_TUPLE=0)
endif()


# Project: CPU dispatch smoke test
# Tiny standalone program that proves hiprtCreateContext(deviceType=hiprtDeviceCPU)
# routes through CpuContext (not GpuContext). It does not need a GPU.
# add_executable(cpu_smoke ${CMAKE_CURRENT_SOURCE_DIR}/test/cpu_smoke.cpp)

# target_include_directories(cpu_smoke PRIVATE
# ${CMAKE_CURRENT_SOURCE_DIR}
# ${CMAKE_CURRENT_SOURCE_DIR}/contrib/Orochi)

# target_link_libraries(cpu_smoke PRIVATE ${HIPRT_NAME})

# if(WIN32)
# target_link_libraries(cpu_smoke PRIVATE version)
# endif()

# if( CMAKE_BUILD_TYPE STREQUAL "Debug" )
# set_target_properties(cpu_smoke PROPERTIES OUTPUT_NAME "cpu_smokeD")
# endif()
22 changes: 22 additions & 0 deletions hiprt/hiprt.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -600,6 +600,28 @@ HIPRT_API hiprtError hiprtSetCacheDirPath( hiprtContext context, const char* pat
*/
HIPRT_API hiprtError hiprtSetLogLevel( hiprtContext context, hiprtLogLevel level );

/** \brief Returns the Embree CpuGeometryData pointer associated with a geometry handle.
*
* Works for both pure-CPU (hiprtDeviceCPU) and hybrid (hiprtDeviceAMD | hiprtDeviceCPU) contexts.
* Returns nullptr if the handle has no CPU mirror (pure GPU context).
* The returned pointer is opaque; cast it to hiprt::CpuGeometryData* in hiprt_cpu.h.
*
* \param geometry The geometry handle.
* \return Pointer to the internal CpuGeometryData, or nullptr.
*/
HIPRT_API void* hiprtGetInternalCpuDataFromGeometry( hiprtGeometry geometry );

/** \brief Returns the Embree CpuSceneData pointer associated with a scene handle.
*
* Works for both pure-CPU (hiprtDeviceCPU) and hybrid (hiprtDeviceAMD | hiprtDeviceCPU) contexts.
* Returns nullptr if the handle has no CPU mirror (pure GPU context).
* The returned pointer is opaque; cast it to hiprt::CpuSceneData* in hiprt_cpu.h.
*
* \param scene The scene handle.
* \return Pointer to the internal CpuSceneData, or nullptr.
*/
HIPRT_API void* hiprtGetInternalCpuDataFromScene( hiprtScene scene );

#ifdef __cplusplus
}
#endif
196 changes: 196 additions & 0 deletions hiprt/hiprt_cpu.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
//////////////////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2024 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////////////////

#pragma once

#include <hiprt/hiprt.h>
#include <hiprt/hiprt_types.h>
#include <hiprt/impl/CpuTypes.h>
#include <embree4/rtcore.h>
#include <embree4/rtcore_ray.h>

// Internal helpers
namespace hiprt_cpu_detail
{

inline RTCRayHit makeRTCRayHit( const hiprtRay& ray ) noexcept
{
RTCRayHit rh{};
rh.ray.org_x = ray.origin.x;
rh.ray.org_y = ray.origin.y;
rh.ray.org_z = ray.origin.z;
rh.ray.dir_x = ray.direction.x;
rh.ray.dir_y = ray.direction.y;
rh.ray.dir_z = ray.direction.z;
rh.ray.tnear = ray.minT;
rh.ray.tfar = ray.maxT;
rh.ray.mask = static_cast<unsigned>( -1 );
rh.ray.flags = 0;
rh.hit.geomID = RTC_INVALID_GEOMETRY_ID;
rh.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
return rh;
}

inline hiprtHit makeHiprtHit( const RTCRayHit& rh ) noexcept
{
hiprtHit hit{};
if ( rh.hit.geomID == RTC_INVALID_GEOMETRY_ID )
return hit;

hit.primID = rh.hit.primID;
hit.instanceID = ( rh.hit.instID[0] != RTC_INVALID_GEOMETRY_ID )
? rh.hit.instID[0]
: hiprtInvalidValue;
hit.uv.x = rh.hit.u;
hit.uv.y = rh.hit.v;
hit.normal.x = rh.hit.Ng_x;
hit.normal.y = rh.hit.Ng_y;
hit.normal.z = rh.hit.Ng_z;
hit.t = rh.ray.tfar;
return hit;
}

inline void traceGeometryBatch(
RTCScene scene, const hiprtRay* rays, hiprtHit* hits, uint32_t count ) noexcept
{
if ( scene == nullptr )
{
for ( uint32_t i = 0; i < count; ++i )
hits[i] = hiprtHit{};
return;
}

for ( uint32_t i = 0; i < count; ++i )
{
RTCRayHit rh = makeRTCRayHit( rays[i] );
rtcIntersect1( scene, &rh );
hits[i] = makeHiprtHit( rh );
}
}

inline RTCRay makeRTCRay( const hiprtRay& ray ) noexcept
{
RTCRay r{};
r.org_x = ray.origin.x;
r.org_y = ray.origin.y;
r.org_z = ray.origin.z;
r.dir_x = ray.direction.x;
r.dir_y = ray.direction.y;
r.dir_z = ray.direction.z;
r.tnear = ray.minT;
r.tfar = ray.maxT;
r.mask = static_cast<unsigned>( -1 );
r.flags = 0;
return r;
}

// Any-hit: rtcOccluded1 result encoded in hit.hasHit().
inline void traceGeometryAnyHitBatch(
RTCScene scene, const hiprtRay* rays, hiprtHit* hits, uint32_t count ) noexcept
{
if ( scene == nullptr )
{
for ( uint32_t i = 0; i < count; ++i )
hits[i] = hiprtHit{};
return;
}

for ( uint32_t i = 0; i < count; ++i )
{
RTCRay r = makeRTCRay( rays[i] );
rtcOccluded1( scene, &r );

hiprtHit hit{};
if ( r.tfar < 0.0f ) // occluded
{
hit.primID = 0;
hit.instanceID = hiprtInvalidValue;
}
hits[i] = hit;
}
}

} // namespace hiprt_cpu_detail

// Host-side CPU batch traversal (Embree).
class hiprtGeomTraversalClosestCPU
{
public:
static void traceBatch(
hiprtContext ctx,
hiprtGeometry geom,
const hiprtRay* rays,
hiprtHit* hits,
uint32_t count ) noexcept
{
(void)ctx;
auto* data = reinterpret_cast<hiprt::CpuGeometryData*>( hiprtGetInternalCpuDataFromGeometry( geom ) );
hiprt_cpu_detail::traceGeometryBatch(
( data != nullptr ) ? data->rtcScene : nullptr, rays, hits, count );
}

static void traceBatch(
hiprtContext ctx,
hiprtScene scene,
const hiprtRay* rays,
hiprtHit* hits,
uint32_t count ) noexcept
{
(void)ctx;
auto* data = reinterpret_cast<hiprt::CpuSceneData*>( hiprtGetInternalCpuDataFromScene( scene ) );
hiprt_cpu_detail::traceGeometryBatch(
( data != nullptr ) ? data->rtcScene : nullptr, rays, hits, count );
}
};

// Any-hit batch traversal (shadow/occlusion rays).
class hiprtGeomTraversalAnyHitCPU
{
public:
static void traceBatch(
hiprtContext ctx,
hiprtGeometry geom,
const hiprtRay* rays,
hiprtHit* hits,
uint32_t count ) noexcept
{
(void)ctx;
auto* data = reinterpret_cast<hiprt::CpuGeometryData*>( hiprtGetInternalCpuDataFromGeometry( geom ) );
hiprt_cpu_detail::traceGeometryAnyHitBatch(
( data != nullptr ) ? data->rtcScene : nullptr, rays, hits, count );
}

static void traceBatch(
hiprtContext ctx,
hiprtScene scene,
const hiprtRay* rays,
hiprtHit* hits,
uint32_t count ) noexcept
{
(void)ctx;
auto* data = reinterpret_cast<hiprt::CpuSceneData*>( hiprtGetInternalCpuDataFromScene( scene ) );
hiprt_cpu_detail::traceGeometryAnyHitBatch(
( data != nullptr ) ? data->rtcScene : nullptr, rays, hits, count );
}
};
Loading