diff --git a/integration/omm-sdk-nvrhi/omm-sdk-nvrhi.cpp b/integration/omm-sdk-nvrhi/omm-sdk-nvrhi.cpp index 526e307..d0a3dcb 100644 --- a/integration/omm-sdk-nvrhi/omm-sdk-nvrhi.cpp +++ b/integration/omm-sdk-nvrhi/omm-sdk-nvrhi.cpp @@ -675,8 +675,8 @@ omm::Gpu::DispatchConfigDesc GpuBakeNvrhiImpl::GetConfig(const GpuBakeNvrhi::Inp config.alphaTextureChannel = params.alphaTextureChannel; config.alphaMode = AlphaMode::Test; config.alphaCutoff = params.alphaCutoff; - config.alphaCutoffGT = params.alphaCutoffGT; - config.alphaCutoffLE = params.alphaCutoffLE; + config.alphaCutoffGreater = params.alphaCutoffGreater; + config.alphaCutoffLessEqual = params.alphaCutoffLessEqual; config.texCoordFormat = GetTexCoordFormat(params.texCoordFormat); config.texCoordOffsetInBytes = params.texCoordBufferOffsetInBytes; config.texCoordStrideInBytes = params.texCoordStrideInBytes; diff --git a/integration/omm-sdk-nvrhi/omm-sdk-nvrhi.h b/integration/omm-sdk-nvrhi/omm-sdk-nvrhi.h index af59402..4fb32ca 100644 --- a/integration/omm-sdk-nvrhi/omm-sdk-nvrhi.h +++ b/integration/omm-sdk-nvrhi/omm-sdk-nvrhi.h @@ -51,8 +51,16 @@ namespace omm nvrhi::TextureHandle alphaTexture; uint32_t alphaTextureChannel = 3; float alphaCutoff = 0.5f; - omm::OpacityState alphaCutoffGT = omm::OpacityState::Opaque; - omm::OpacityState alphaCutoffLE = omm::OpacityState::Transparent; + union { + OMM_DEPRECATED_MSG("alphaCutoffGT is deprectated, please use alphaCutoffGreater") + omm::OpacityState alphaCutoffGT; + omm::OpacityState alphaCutoffGreater = omm::OpacityState::Opaque; + }; + union { + OMM_DEPRECATED_MSG("alphaCutoffLT is deprectated, please use alphaCutoffLessEqual") + omm::OpacityState alphaCutoffLT; + omm::OpacityState alphaCutoffLessEqual = omm::OpacityState::Transparent; + }; bool bilinearFilter = true; bool enableLevelLineIntersection = true; nvrhi::SamplerAddressMode sampleMode = nvrhi::SamplerAddressMode::Clamp; diff --git a/omm-sdk/include/omm.h b/omm-sdk/include/omm.h index e88a909..2efd5ca 100644 --- a/omm-sdk/include/omm.h +++ b/omm-sdk/include/omm.h @@ -15,7 +15,7 @@ license agreement from NVIDIA CORPORATION is strictly prohibited. #include #define OMM_VERSION_MAJOR 1 -#define OMM_VERSION_MINOR 3 +#define OMM_VERSION_MINOR 4 #define OMM_VERSION_BUILD 0 #define OMM_MAX_TRANSIENT_POOL_BUFFERS 8 @@ -54,13 +54,20 @@ license agreement from NVIDIA CORPORATION is strictly prohibited. typedef uint8_t ommBool; -typedef uintptr_t ommHandle; +typedef struct _ommBaker _ommBaker; +typedef _ommBaker* ommBaker; -typedef ommHandle ommBaker; +typedef struct _ommCpuBakeResult _ommCpuBakeResult; +typedef _ommCpuBakeResult* ommCpuBakeResult; -typedef ommHandle ommCpuBakeResult; +typedef struct _ommCpuTexture _ommCpuTexture; +typedef _ommCpuTexture* ommCpuTexture; -typedef ommHandle ommCpuTexture; +typedef struct _ommCpuSerializedResult _ommCpuSerializedResult; +typedef _ommCpuSerializedResult* ommCpuSerializedResult; + +typedef struct _ommCpuDeserializedResult _ommCpuDeserializedResult; +typedef _ommCpuDeserializedResult* ommCpuDeserializedResult; typedef void* (*ommAllocate)(void* userArg, size_t size, size_t alignment); @@ -75,7 +82,7 @@ typedef enum ommResult ommResult_INVALID_ARGUMENT, ommResult_INSUFFICIENT_SCRATCH_MEMORY, ommResult_NOT_IMPLEMENTED, - ommResult_WORKLOAD_TOO_BIG OMM_DEPRECATED_MSG("ommResult_WORKLOAD_TOO_BIG has been deprecated and will no longer be returned. Enable logging to look for perf warnings instead."), + ommResult_WORKLOAD_TOO_BIG, ommResult_MAX_NUM, } ommResult; @@ -83,6 +90,7 @@ typedef enum ommMessageSeverity { ommMessageSeverity_Info, ommMessageSeverity_PerfWarning, + ommMessageSeverity_Error, ommMessageSeverity_Fatal, ommMessageSeverity_MAX_NUM, } ommMessageSeverity; @@ -173,6 +181,12 @@ typedef enum ommAlphaMode ommAlphaMode_MAX_NUM, } ommAlphaMode; +typedef enum ommCpuSerializeFlags +{ + ommCpuSerializeFlags_None, + ommCpuSerializeFlags_Compress, +} ommCpuSerializeFlags; + typedef struct ommLibraryDesc { uint8_t versionMajor; @@ -384,8 +398,18 @@ typedef struct ommCpuBakeInputDesc // Texel opacity = texture > alphaCutoff ? alphaCutoffGT : alphaCutoffLE // This can be used to construct different pairings such as transparent and unknown opaque which is useful // for applications requiring partial accumulated opacity, like smoke and particle effects - ommOpacityState alphaCutoffLE; - ommOpacityState alphaCutoffGT; + union + { + OMM_DEPRECATED_MSG("alphaCutoffLE has been deprecated, please use alphaCutoffLessEqual") + ommOpacityState alphaCutoffLE; + ommOpacityState alphaCutoffLessEqual; + }; + union + { + OMM_DEPRECATED_MSG("alphaCutoffGT has been deprecated, please use alphaCutoffGreater instead") + ommOpacityState alphaCutoffGT; + ommOpacityState alphaCutoffGreater; + }; // The global Format. May be overriden by the per-triangle subdivision level setting. ommFormat format; // Use Formats to control format on a per triangle granularity. If Format is set to Format::INVALID the global setting will @@ -399,12 +423,21 @@ typedef struct ommCpuBakeInputDesc // When dynamicSubdivisionScale is disabled maxSubdivisionLevel is the subdivision level applied uniformly to all // triangles. uint8_t maxSubdivisionLevel; - ommBool enableSubdivisionLevelBuffer; // [optional] Use subdivisionLevels to control subdivision on a per triangle granularity. // +14 - reserved for future use. // 13 - use global value specified in 'subdivisionLevel. // [0,12] - per triangle subdivision level' const uint8_t* subdivisionLevels; + // [optional] Use maxWorkloadSize to cancel baking when the workload (# micro-triangle / texel tests) increase a certain threshold. + // The baker will either reduce the baking quality to fit within this computational budget, or fail completely by returning the error code ommResult_WORKLOAD_TOO_BIG + // This value correlates to the amount of processing required in the OMM bake call. + // Factors that influence this value is: + // * Number of unique UVs + // * Size of the UVs + // * Resolution of the underlying alpha texture + // * Subdivision level of the OMMs. + // Configure this value when experiencing long bake times, a starting point might be maxWorkloadSize = 1 << 28 (~ processing a total of 256 1k textures) + uint64_t maxWorkloadSize; } ommCpuBakeInputDesc; inline ommCpuBakeInputDesc ommCpuBakeInputDescDefault() @@ -423,14 +456,14 @@ inline ommCpuBakeInputDesc ommCpuBakeInputDescDefault() v.dynamicSubdivisionScale = 2; v.rejectionThreshold = 0; v.alphaCutoff = 0.5f; - v.alphaCutoffLE = ommOpacityState_Transparent; - v.alphaCutoffGT = ommOpacityState_Opaque; + v.alphaCutoffLessEqual = ommOpacityState_Transparent; + v.alphaCutoffGreater = ommOpacityState_Opaque; v.format = ommFormat_OC1_4_State; v.formats = NULL; v.unknownStatePromotion = ommUnknownStatePromotion_ForceOpaque; v.maxSubdivisionLevel = 8; - v.enableSubdivisionLevelBuffer = 0; v.subdivisionLevels = NULL; + v.maxWorkloadSize = 0; return v; } @@ -474,6 +507,42 @@ typedef struct ommCpuBakeResultDesc uint32_t indexHistogramCount; } ommCpuBakeResultDesc; +typedef struct ommCpuBlobDesc +{ + void* data; + uint64_t size; +} ommCpuBlobDesc; + +inline ommCpuBlobDesc ommCpuBlobDescDefault() +{ + ommCpuBlobDesc v; + v.data = nullptr; + v.size = 0; + return v; +} + +typedef struct ommCpuDeserializedDesc +{ + ommCpuSerializeFlags flags; + // Optional + int numInputDescs; + const ommCpuBakeInputDesc* inputDescs; + // Optional + int numResultDescs; + const ommCpuBakeResultDesc* resultDescs; +} ommCpuDeserializedDesc; + +inline ommCpuDeserializedDesc ommCpuDeserializedDescDefault() +{ + ommCpuDeserializedDesc v; + v.flags = ommCpuSerializeFlags_None; + v.numInputDescs = 0; + v.inputDescs = nullptr; + v.numResultDescs = 0; + v.resultDescs = nullptr; + return v; +} + OMM_API ommResult ommCpuCreateTexture(ommBaker baker, const ommCpuTextureDesc* desc, ommCpuTexture* outTexture); OMM_API ommResult ommCpuDestroyTexture(ommBaker baker, ommCpuTexture texture); @@ -484,7 +553,24 @@ OMM_API ommResult ommCpuDestroyBakeResult(ommCpuBakeResult bakeResult); OMM_API ommResult ommCpuGetBakeResultDesc(ommCpuBakeResult bakeResult, const ommCpuBakeResultDesc** desc); -typedef ommHandle ommGpuPipeline; +// Serialization API useful to distribute input and /or output data for debugging& visualization purposes + +// Serialization +OMM_API ommResult ommCpuSerialize(ommBaker baker, const ommCpuDeserializedDesc& desc, ommCpuSerializedResult* outResult); + +OMM_API ommResult ommCpuGetSerializedResultDesc(ommCpuSerializedResult result, const ommCpuBlobDesc** desc); + +OMM_API ommResult ommCpuDestroySerializedResult(ommCpuSerializedResult result); + +// Deserialization +OMM_API ommResult ommCpuDeserialize(ommBaker baker, const ommCpuBlobDesc& desc, ommCpuDeserializedResult* outResult); + +OMM_API ommResult ommCpuGetDeserializedDesc(ommCpuDeserializedResult result, const ommCpuDeserializedDesc** desc); + +OMM_API ommResult ommCpuDestroyDeserializedResult(ommCpuDeserializedResult result); + +typedef struct _ommGpuPipeline _ommGpuPipeline; +typedef _ommGpuPipeline* ommGpuPipeline; typedef enum ommGpuDescriptorType { @@ -908,8 +994,18 @@ typedef struct ommGpuDispatchConfigDesc // Texel opacity = texture > alphaCutoff ? alphaCutoffGT : alphaCutoffLE // This can be used to construct different pairings such as transparent and unknown opaque which is useful // for applications requiring partial accumulated opacity, like smoke and particle effects - ommOpacityState alphaCutoffLE; - ommOpacityState alphaCutoffGT; + union + { + OMM_DEPRECATED_MSG("alphaCutoffLE has been deprecated, please use alphaCutoffLessEqual") + ommOpacityState alphaCutoffLE; + ommOpacityState alphaCutoffLessEqual; + }; + union + { + OMM_DEPRECATED_MSG("alphaCutoffGT has been deprecated, please use alphaCutoffGreater instead") + ommOpacityState alphaCutoffGT; + ommOpacityState alphaCutoffGreater; + }; // Configure the target resolution when running dynamic subdivision level. <= 0: disabled. > 0: The subdivision level be // chosen such that a single micro-triangle covers approximatley a dynamicSubdivisionScale * dynamicSubdivisionScale texel // area. @@ -946,8 +1042,8 @@ inline ommGpuDispatchConfigDesc ommGpuDispatchConfigDescDefault() v.indexCount = 0; v.indexStrideInBytes = 0; v.alphaCutoff = 0.5f; - v.alphaCutoffLE = ommOpacityState_Transparent; - v.alphaCutoffGT = ommOpacityState_Opaque; + v.alphaCutoffLessEqual = ommOpacityState_Transparent; + v.alphaCutoffGreater = ommOpacityState_Opaque; v.dynamicSubdivisionScale = 2; v.globalFormat = ommFormat_OC1_4_State; v.maxSubdivisionLevel = 8; @@ -1042,9 +1138,6 @@ inline ommDebugSaveImagesDesc ommDebugSaveImagesDescDefault() return v; } -// Walk each primitive and dumps the corresponding OMM overlay to the alpha textures. -OMM_API ommResult ommDebugSaveAsImages(ommBaker baker, const ommCpuBakeInputDesc* bakeInputDesc, const ommCpuBakeResultDesc* res, const ommDebugSaveImagesDesc* desc); - typedef struct ommDebugStats { uint64_t totalOpaque; @@ -1071,5 +1164,11 @@ inline ommDebugStats ommDebugStatsDefault() return v; } +// Walk each primitive and dumps the corresponding OMM overlay to the alpha textures. +OMM_API ommResult ommDebugSaveAsImages(ommBaker baker, const ommCpuBakeInputDesc* bakeInputDesc, const ommCpuBakeResultDesc* res, const ommDebugSaveImagesDesc* desc); + OMM_API ommResult ommDebugGetStats(ommBaker baker, const ommCpuBakeResultDesc* res, ommDebugStats* out); + +OMM_API ommResult ommDebugSaveBinaryToDisk(ommBaker baker, const ommCpuBlobDesc& data, const char* path); + #endif // #ifndef INCLUDE_OMM_SDK_C diff --git a/omm-sdk/include/omm.hpp b/omm-sdk/include/omm.hpp index 7f08158..0aa02a3 100644 --- a/omm-sdk/include/omm.hpp +++ b/omm-sdk/include/omm.hpp @@ -23,7 +23,7 @@ namespace omm INVALID_ARGUMENT, INSUFFICIENT_SCRATCH_MEMORY, NOT_IMPLEMENTED, - WORKLOAD_TOO_BIG OMM_DEPRECATED_MSG("WORKLOAD_TOO_BIG has been deprecated and will no longer be returned. Enable logging to look for perf warnings instead."), + WORKLOAD_TOO_BIG, MAX_NUM, }; @@ -171,9 +171,7 @@ namespace omm MessageInterface messageInterface = {}; }; - using Handle = uintptr_t; - - using Baker = Handle; + typedef ommBaker Baker; static inline LibraryDesc GetLibraryDesc(); @@ -183,10 +181,13 @@ namespace omm namespace Cpu { + typedef ommCpuBakeResult BakeResult; + + typedef ommCpuTexture Texture; - using BakeResult = Handle; + typedef ommCpuSerializedResult SerializedResult; - using Texture = Handle; + typedef ommCpuDeserializedResult DeserializedResult; enum class TextureFormat { @@ -236,6 +237,13 @@ namespace omm }; OMM_DEFINE_ENUM_FLAG_OPERATORS(BakeFlags); + enum class SerializeFlags + { + None, + Compress, + }; + OMM_DEFINE_ENUM_FLAG_OPERATORS(SerializeFlags); + // The baker supports conservativle baking from a MIP array when the runtime wants to pick freely between texture levels at // runtime without the need to update the OMM data. _However_ baking from mip level 0 only is recommended in the general // case for best performance the integration guide contains more in depth discussion on the topic @@ -283,11 +291,21 @@ namespace omm // The alpha cutoff value. By default it's Texel Opacity = texture > alphaCutoff ? Opaque : Transparent float alphaCutoff = 0.5f; // alphaCutoffGT and alphaCutoffLE allows dynamic configuring of the alpha values in the texture in the following way: - // Texel opacity = texture > alphaCutoff ? alphaCutoffGT : alphaCutoffLE + // Texel Opacity = texture > alphaCutoff ? alphaCutoffGreater : alphaCutoffLessEqual // This can be used to construct different pairings such as transparent and unknown opaque which is useful // for applications requiring partial accumulated opacity, like smoke and particle effects - omm::OpacityState alphaCutoffLE = omm::OpacityState::Transparent; - omm::OpacityState alphaCutoffGT = omm::OpacityState::Opaque; + union + { + OMM_DEPRECATED_MSG("alphaCutoffLE has been deprecated, please use alphaCutoffLessEqual") + omm::OpacityState alphaCutoffLE; + omm::OpacityState alphaCutoffLessEqual = omm::OpacityState::Transparent; + }; + union + { + OMM_DEPRECATED_MSG("alphaCutoffGT has been deprecated, please use alphaCutoffGreater instead") + omm::OpacityState alphaCutoffGT; + omm::OpacityState alphaCutoffGreater = omm::OpacityState::Opaque; + }; // The global Format. May be overriden by the per-triangle subdivision level setting. Format format = Format::OC1_4_State; // Use Formats to control format on a per triangle granularity. If Format is set to Format::INVALID the global setting will @@ -301,12 +319,21 @@ namespace omm // When dynamicSubdivisionScale is disabled maxSubdivisionLevel is the subdivision level applied uniformly to all // triangles. uint8_t maxSubdivisionLevel = 8; - bool enableSubdivisionLevelBuffer = false; // [optional] Use subdivisionLevels to control subdivision on a per triangle granularity. // +14 - reserved for future use. // 13 - use global value specified in 'subdivisionLevel. // [0,12] - per triangle subdivision level' const uint8_t* subdivisionLevels = nullptr; + // [optional] Use maxWorkloadSize to cancel baking when the workload (# micro-triangle / texel tests) increase a certain threshold. + // The baker will either reduce the baking quality to fit within this computational budget, or fail completely by returning the error code ommResult_WORKLOAD_TOO_BIG + // This value correlates to the amount of processing required in the OMM bake call. + // Factors that influence this value is: + // * Number of unique UVs + // * Size of the UVs + // * Resolution of the underlying alpha texture + // * Subdivision level of the OMMs. + // Configure this value when experiencing long bake times, a starting point might be maxWorkloadSize = 1 << 28 (~ processing a total of 256 1k textures) + uint64_t maxWorkloadSize = 0xFFFFFFFFFFFFFFFF; }; struct OpacityMicromapDesc @@ -349,6 +376,23 @@ namespace omm uint32_t indexHistogramCount; }; + struct BlobDesc + { + void* data = nullptr; + uint64_t size = 0; + }; + + struct DeserializedDesc + { + SerializeFlags flags = SerializeFlags::None; + // Optional + int numInputDescs = 0; + const BakeInputDesc* inputDescs = nullptr; + // Optional + int numResultDescs = 0; + const BakeResultDesc* resultDescs = nullptr; + }; + static inline Result CreateTexture(Baker baker, const TextureDesc& desc, Texture* outTexture); static inline Result DestroyTexture(Baker baker, Texture texture); @@ -359,12 +403,25 @@ namespace omm static inline Result GetBakeResultDesc(BakeResult bakeResult, const BakeResultDesc** desc); + static inline Result Serialize(ommBaker baker, const DeserializedDesc& inputDesc, SerializedResult* outResult); + + static inline Result GetSerializedResultDesc(SerializedResult result, const BlobDesc** desc); + + static inline Result DestroySerializedResult(SerializedResult result); + + static inline Result Deserialize(ommBaker baker, const BlobDesc& desc, DeserializedResult* outResult); + + static inline Result GetDeserializedDesc(DeserializedResult result, const DeserializedDesc** desc); + + static inline Result DestroyDeserializedResult(DeserializedResult result); + } // namespace Cpu namespace Gpu { - using Pipeline = Handle; + typedef struct _Pipeline _Pipeline; + typedef _Pipeline* Pipeline; enum class DescriptorType { @@ -752,11 +809,21 @@ namespace omm // The alpha cutoff value. By default it's Texel Opacity = texture > alphaCutoff ? Opaque : Transparent float alphaCutoff = 0.5f; // alphaCutoffGT and alphaCutoffLE allows dynamic configuring of the alpha values in the texture in the following way: - // Texel Opacity = texture > alphaCutoff ? alphaCutoffGT : alphaCutoffLE + // Texel Opacity = texture > alphaCutoff ? alphaCutoffGreater : alphaCutoffLessEqual // This can be used to construct different pairings such as transparent and unknown opaque which is useful // for applications requiring partial accumulated opacity, like smoke and particle effects - omm::OpacityState alphaCutoffLE = omm::OpacityState::Transparent; - omm::OpacityState alphaCutoffGT = omm::OpacityState::Opaque; + union + { + OMM_DEPRECATED_MSG("alphaCutoffLE has been deprecated, please use alphaCutoffLessEqual") + omm::OpacityState alphaCutoffLE; + omm::OpacityState alphaCutoffLessEqual = omm::OpacityState::Transparent; + }; + union + { + OMM_DEPRECATED_MSG("alphaCutoffGT has been deprecated, please use alphaCutoffGreater instead") + omm::OpacityState alphaCutoffGT; + omm::OpacityState alphaCutoffGreater = omm::OpacityState::Opaque; + }; // Configure the target resolution when running dynamic subdivision level. <= 0: disabled. > 0: The subdivision level be // chosen such that a single micro-triangle covers approximatley a dynamicSubdivisionScale * dynamicSubdivisionScale texel // area. @@ -878,81 +945,109 @@ namespace omm namespace omm { - static inline LibraryDesc GetLibraryDesc() - { + static inline LibraryDesc GetLibraryDesc() + { ommLibraryDesc res = ommGetLibraryDesc(); return reinterpret_cast(res); - } - static inline Result CreateBaker(const BakerCreationDesc& bakeCreationDesc, Baker* outBaker) - { - static_assert(sizeof(BakerCreationDesc) == sizeof(ommBakerCreationDesc)); - return (Result)ommCreateBaker(reinterpret_cast(&bakeCreationDesc), (ommBaker*)outBaker); - } - static inline Result DestroyBaker(Baker baker) - { - return (Result)ommDestroyBaker((ommBaker)baker); - } - namespace Cpu - { - static inline Result CreateTexture(Baker baker, const TextureDesc& desc, Texture* outTexture) - { - return (Result)ommCpuCreateTexture((ommBaker)baker, reinterpret_cast(&desc), (ommCpuTexture*)outTexture); - } - static inline Result DestroyTexture(Baker baker, Texture texture) - { - return (Result)ommCpuDestroyTexture((ommBaker)baker, (ommCpuTexture)texture); - } - static inline Result Bake(Baker baker, const BakeInputDesc& bakeInputDesc, BakeResult* outBakeResult) - { - return (Result)ommCpuBake((ommBaker)baker, reinterpret_cast(&bakeInputDesc), (ommCpuBakeResult*)outBakeResult); - } - static inline Result DestroyBakeResult(BakeResult bakeResult) - { - return (Result)ommCpuDestroyBakeResult((ommCpuBakeResult)bakeResult); - } - static inline Result GetBakeResultDesc(BakeResult bakeResult, const BakeResultDesc** desc) - { - return (Result)ommCpuGetBakeResultDesc((ommCpuBakeResult)bakeResult, reinterpret_cast(desc)); - } - } - namespace Gpu - { - static inline Result GetStaticResourceData(ResourceType resource, uint8_t* data, size_t* outByteSize) - { - return (Result)ommGpuGetStaticResourceData((ommGpuResourceType)resource, data, outByteSize); - } - static inline Result CreatePipeline(Baker baker, const PipelineConfigDesc& pipelineCfg, Pipeline* outPipeline) - { - return (Result)ommGpuCreatePipeline((ommBaker)baker, reinterpret_cast(&pipelineCfg), (ommGpuPipeline*)outPipeline); - } - static inline Result DestroyPipeline(Baker baker, Pipeline pipeline) - { - return (Result)ommGpuDestroyPipeline((ommBaker)baker, (ommGpuPipeline)pipeline); - } - static inline Result GetPipelineDesc(Pipeline pipeline, const PipelineInfoDesc** outPipelineDesc) - { - return (Result)ommGpuGetPipelineDesc((ommGpuPipeline)pipeline, reinterpret_cast(outPipelineDesc)); - } - static inline Result GetPreDispatchInfo(Pipeline pipeline, const DispatchConfigDesc& config, PreDispatchInfo* outPreBuildInfo) - { - return (Result)ommGpuGetPreDispatchInfo((ommGpuPipeline)pipeline, reinterpret_cast(&config), reinterpret_cast(outPreBuildInfo)); - } - static inline Result Dispatch(Pipeline pipeline, const DispatchConfigDesc& config, const DispatchChain** outDispatchDesc) - { - return (Result)ommGpuDispatch((ommGpuPipeline)pipeline, reinterpret_cast(&config), reinterpret_cast(outDispatchDesc)); - } - } - namespace Debug - { - static inline Result SaveAsImages(Baker baker, const Cpu::BakeInputDesc& bakeInputDesc, const Cpu::BakeResultDesc* res, const SaveImagesDesc& desc) - { - return (Result)ommDebugSaveAsImages((ommBaker)baker, reinterpret_cast(&bakeInputDesc), reinterpret_cast(res), reinterpret_cast(&desc)); - } - static inline Result GetStats(Baker baker, const Cpu::BakeResultDesc* res, Stats* out) - { - return (Result)ommDebugGetStats((ommBaker)baker, reinterpret_cast(res), reinterpret_cast(out)); - } - } + } + static inline Result CreateBaker(const BakerCreationDesc& bakeCreationDesc, Baker* outBaker) + { + static_assert(sizeof(BakerCreationDesc) == sizeof(ommBakerCreationDesc)); + return (Result)ommCreateBaker(reinterpret_cast(&bakeCreationDesc), (ommBaker*)outBaker); + } + static inline Result DestroyBaker(Baker baker) + { + return (Result)ommDestroyBaker((ommBaker)baker); + } + namespace Cpu + { + static inline Result CreateTexture(Baker baker, const TextureDesc& desc, Texture* outTexture) + { + return (Result)ommCpuCreateTexture((ommBaker)baker, reinterpret_cast(&desc), (ommCpuTexture*)outTexture); + } + static inline Result DestroyTexture(Baker baker, Texture texture) + { + return (Result)ommCpuDestroyTexture((ommBaker)baker, (ommCpuTexture)texture); + } + static inline Result Bake(Baker baker, const BakeInputDesc& bakeInputDesc, BakeResult* outBakeResult) + { + return (Result)ommCpuBake((ommBaker)baker, reinterpret_cast(&bakeInputDesc), (ommCpuBakeResult*)outBakeResult); + } + static inline Result DestroyBakeResult(BakeResult bakeResult) + { + return (Result)ommCpuDestroyBakeResult((ommCpuBakeResult)bakeResult); + } + static inline Result GetBakeResultDesc(BakeResult bakeResult, const BakeResultDesc** desc) + { + return (Result)ommCpuGetBakeResultDesc((ommCpuBakeResult)bakeResult, reinterpret_cast(desc)); + } + static inline Result Serialize(ommBaker baker, const DeserializedDesc& desc, SerializedResult* outResult) + { + return (Result)ommCpuSerialize(baker, reinterpret_cast(desc), reinterpret_cast(outResult)); + } + static inline Result GetSerializedResultDesc(SerializedResult result, const BlobDesc** desc) + { + return (Result)ommCpuGetSerializedResultDesc((ommCpuSerializedResult)result, reinterpret_cast(desc)); + } + static inline Result DestroySerializedResult(SerializedResult result) + { + return (Result)ommCpuDestroySerializedResult((ommCpuSerializedResult)result); + } + static inline Result Deserialize(ommBaker baker, const BlobDesc& desc, DeserializedResult* outResult) + { + return (Result)ommCpuDeserialize(baker, reinterpret_cast(desc), reinterpret_cast(outResult)); + } + static inline Result GetDeserializedDesc(DeserializedResult result, const DeserializedDesc** desc) + { + return (Result)ommCpuGetDeserializedDesc((ommCpuDeserializedResult)result, reinterpret_cast(desc)); + } + static inline Result DestroyDeserializedResult(DeserializedResult result) + { + return (Result)ommCpuDestroyDeserializedResult((ommCpuDeserializedResult)result); + } + } + namespace Gpu + { + static inline Result GetStaticResourceData(ResourceType resource, uint8_t* data, size_t* outByteSize) + { + return (Result)ommGpuGetStaticResourceData((ommGpuResourceType)resource, data, outByteSize); + } + static inline Result CreatePipeline(Baker baker, const PipelineConfigDesc& pipelineCfg, Pipeline* outPipeline) + { + return (Result)ommGpuCreatePipeline((ommBaker)baker, reinterpret_cast(&pipelineCfg), (ommGpuPipeline*)outPipeline); + } + static inline Result DestroyPipeline(Baker baker, Pipeline pipeline) + { + return (Result)ommGpuDestroyPipeline((ommBaker)baker, (ommGpuPipeline)pipeline); + } + static inline Result GetPipelineDesc(Pipeline pipeline, const PipelineInfoDesc** outPipelineDesc) + { + return (Result)ommGpuGetPipelineDesc((ommGpuPipeline)pipeline, reinterpret_cast(outPipelineDesc)); + } + static inline Result GetPreDispatchInfo(Pipeline pipeline, const DispatchConfigDesc& config, PreDispatchInfo* outPreBuildInfo) + { + return (Result)ommGpuGetPreDispatchInfo((ommGpuPipeline)pipeline, reinterpret_cast(&config), reinterpret_cast(outPreBuildInfo)); + } + static inline Result Dispatch(Pipeline pipeline, const DispatchConfigDesc& config, const DispatchChain** outDispatchDesc) + { + return (Result)ommGpuDispatch((ommGpuPipeline)pipeline, reinterpret_cast(&config), reinterpret_cast(outDispatchDesc)); + } + } + namespace Debug + { + static inline Result SaveAsImages(Baker baker, const Cpu::BakeInputDesc& bakeInputDesc, const Cpu::BakeResultDesc* res, const SaveImagesDesc& desc) + { + return (Result)ommDebugSaveAsImages((ommBaker)baker, reinterpret_cast(&bakeInputDesc), reinterpret_cast(res), reinterpret_cast(&desc)); + } + static inline Result GetStats(Baker baker, const Cpu::BakeResultDesc* res, Stats* out) + { + return (Result)ommDebugGetStats((ommBaker)baker, reinterpret_cast(res), reinterpret_cast(out)); + } + static inline Result SaveBinaryToDisk(Baker baker, const Cpu::BlobDesc& data, const char* path) + { + return (Result)ommDebugSaveBinaryToDisk((ommBaker)baker, reinterpret_cast(data), path); + } + } } #endif // #ifndef INCLUDE_OMM_SDK_CPP diff --git a/omm-sdk/shaders/omm_clear_buffer.cs.resources.hlsli b/omm-sdk/shaders/omm_clear_buffer.cs.resources.hlsli index dd437c1..2976d2b 100644 --- a/omm-sdk/shaders/omm_clear_buffer.cs.resources.hlsli +++ b/omm-sdk/shaders/omm_clear_buffer.cs.resources.hlsli @@ -14,11 +14,11 @@ license agreement from NVIDIA CORPORATION is strictly prohibited. OMM_OUTPUT_RESOURCE( RWByteAddressBuffer, u_targetBuffer, u, 0 ) #define OMM_DECLARE_LOCAL_CONSTANT_BUFFER \ -OMM_PUSH_CONSTANTS_START(LocalConstants) \ +OMM_PUSH_CONSTANTS_START(LocalConstants) \ \ - OMM_PUSH_CONSTANT(uint, ClearValue) \ - OMM_PUSH_CONSTANT(uint, NumElements) \ - OMM_PUSH_CONSTANT(uint, BufferOffset) \ - OMM_PUSH_CONSTANT(uint, gPad0) \ + OMM_PUSH_CONSTANT(uint, ClearValue) \ + OMM_PUSH_CONSTANT(uint, NumElements) \ + OMM_PUSH_CONSTANT(uint, BufferOffset) \ + OMM_PUSH_CONSTANT(uint, gPad0) \ \ OMM_PUSH_CONSTANTS_END(LocalConstants, 1) diff --git a/omm-sdk/shaders/omm_common.hlsli b/omm-sdk/shaders/omm_common.hlsli index 8932374..3e1273e 100644 --- a/omm-sdk/shaders/omm_common.hlsli +++ b/omm-sdk/shaders/omm_common.hlsli @@ -8,8 +8,8 @@ distribution of this software and related documentation without an express license agreement from NVIDIA CORPORATION is strictly prohibited. */ -#ifndef WORK_SETUP_COMMON_HLSLI -#define WORK_SETUP_COMMON_HLSLI +#ifndef OMM_COMMON_HLSLI +#define OMM_COMMON_HLSLI #include "omm_platform.hlsli" #include "omm.hlsli" @@ -124,23 +124,23 @@ TexCoords FetchTexCoords(Buffer indexBuffer, ByteAddressBuffer texCoordBuf float2 vertexUVs[3]; - if ((TexCoordFormat)g_GlobalConstants.TexCoord1Format == TexCoordFormat::UV16_UNORM) + if ((TexCoordFormat)g_GlobalConstants.TexCoordFormat == TexCoordFormat::UV16_UNORM) { - vertexUVs[0] = UnpackUNORM16Pair(texCoordBuffer.Load(g_GlobalConstants.TexCoord1Offset + indices.x * g_GlobalConstants.TexCoord1Stride)); - vertexUVs[1] = UnpackUNORM16Pair(texCoordBuffer.Load(g_GlobalConstants.TexCoord1Offset + indices.y * g_GlobalConstants.TexCoord1Stride)); - vertexUVs[2] = UnpackUNORM16Pair(texCoordBuffer.Load(g_GlobalConstants.TexCoord1Offset + indices.z * g_GlobalConstants.TexCoord1Stride)); + vertexUVs[0] = UnpackUNORM16Pair(texCoordBuffer.Load(g_GlobalConstants.TexCoordOffset + indices.x * g_GlobalConstants.TexCoordStride)); + vertexUVs[1] = UnpackUNORM16Pair(texCoordBuffer.Load(g_GlobalConstants.TexCoordOffset + indices.y * g_GlobalConstants.TexCoordStride)); + vertexUVs[2] = UnpackUNORM16Pair(texCoordBuffer.Load(g_GlobalConstants.TexCoordOffset + indices.z * g_GlobalConstants.TexCoordStride)); } - else if ((TexCoordFormat)g_GlobalConstants.TexCoord1Format == TexCoordFormat::UV16_FLOAT) + else if ((TexCoordFormat)g_GlobalConstants.TexCoordFormat == TexCoordFormat::UV16_FLOAT) { - vertexUVs[0] = UnpackFP16Pair(texCoordBuffer.Load(g_GlobalConstants.TexCoord1Offset + indices.x * g_GlobalConstants.TexCoord1Stride)); - vertexUVs[1] = UnpackFP16Pair(texCoordBuffer.Load(g_GlobalConstants.TexCoord1Offset + indices.y * g_GlobalConstants.TexCoord1Stride)); - vertexUVs[2] = UnpackFP16Pair(texCoordBuffer.Load(g_GlobalConstants.TexCoord1Offset + indices.z * g_GlobalConstants.TexCoord1Stride)); + vertexUVs[0] = UnpackFP16Pair(texCoordBuffer.Load(g_GlobalConstants.TexCoordOffset + indices.x * g_GlobalConstants.TexCoordStride)); + vertexUVs[1] = UnpackFP16Pair(texCoordBuffer.Load(g_GlobalConstants.TexCoordOffset + indices.y * g_GlobalConstants.TexCoordStride)); + vertexUVs[2] = UnpackFP16Pair(texCoordBuffer.Load(g_GlobalConstants.TexCoordOffset + indices.z * g_GlobalConstants.TexCoordStride)); } - else // if (g_GlobalConstants.TexCoord1Format == TexCoordFormat::UV32_FLOAT) + else // if (g_GlobalConstants.TexCoordFormat == TexCoordFormat::UV32_FLOAT) { - vertexUVs[0] = asfloat(texCoordBuffer.Load2(g_GlobalConstants.TexCoord1Offset + indices.x * g_GlobalConstants.TexCoord1Stride)); - vertexUVs[1] = asfloat(texCoordBuffer.Load2(g_GlobalConstants.TexCoord1Offset + indices.y * g_GlobalConstants.TexCoord1Stride)); - vertexUVs[2] = asfloat(texCoordBuffer.Load2(g_GlobalConstants.TexCoord1Offset + indices.z * g_GlobalConstants.TexCoord1Stride)); + vertexUVs[0] = asfloat(texCoordBuffer.Load2(g_GlobalConstants.TexCoordOffset + indices.x * g_GlobalConstants.TexCoordStride)); + vertexUVs[1] = asfloat(texCoordBuffer.Load2(g_GlobalConstants.TexCoordOffset + indices.y * g_GlobalConstants.TexCoordStride)); + vertexUVs[2] = asfloat(texCoordBuffer.Load2(g_GlobalConstants.TexCoordOffset + indices.z * g_GlobalConstants.TexCoordStride)); } TexCoords tex; @@ -261,4 +261,4 @@ int GetOmmDescOffset(ByteAddressBuffer ommIndexBuffer, uint primitiveIndex) } } -#endif // WORK_SETUP_COMMON_HLSLI \ No newline at end of file +#endif // OMM_COMMON_HLSLI \ No newline at end of file diff --git a/omm-sdk/shaders/omm_compress.cs.hlsl b/omm-sdk/shaders/omm_compress.cs.hlsl index 9925697..fbd8a65 100644 --- a/omm-sdk/shaders/omm_compress.cs.hlsl +++ b/omm-sdk/shaders/omm_compress.cs.hlsl @@ -101,7 +101,7 @@ void main(uint3 tid : SV_DispatchThreadID) const uint2 counts = OMM_SUBRESOURCE_LOAD2(BakeResultBuffer, vmBakeResultOffset); OMM_SUBRESOURCE_STORE2(BakeResultBuffer, vmBakeResultOffset, 0); // clear for next iteration - OpacityState opacityState = GetOpacityState(/*numOpaque*/ counts.x, /*numTransparent*/ counts.y, g_GlobalConstants.AlphaCutoffGT, g_GlobalConstants.AlphaCutoffLE, vmFormat); + OpacityState opacityState = GetOpacityState(/*numOpaque*/ counts.x, /*numTransparent*/ counts.y, g_GlobalConstants.AlphaCutoffGreater, g_GlobalConstants.AlphaCutoffLessEqual, vmFormat); if (microTriangleIndex < numMicroTrianglesPerPrimitive) StoreMacroTriangleState(opacityState, vmPrimitiveIndex); @@ -132,7 +132,7 @@ void main(uint3 tid : SV_DispatchThreadID) const uint2 counts = OMM_SUBRESOURCE_LOAD2(BakeResultBuffer, vmBakeResultOffset); OMM_SUBRESOURCE_STORE2(BakeResultBuffer, vmBakeResultOffset, 0); // clear for next iteration - OpacityState opacityState = GetOpacityState(/*numOpaque*/ counts.x, /*numTransparent*/ counts.y, g_GlobalConstants.AlphaCutoffGT, g_GlobalConstants.AlphaCutoffLE, vmFormat); + OpacityState opacityState = GetOpacityState(/*numOpaque*/ counts.x, /*numTransparent*/ counts.y, g_GlobalConstants.AlphaCutoffGreater, g_GlobalConstants.AlphaCutoffLessEqual, vmFormat); if (microTriangleIndex < numMicroTrianglesPerPrimitive) StoreMacroTriangleState(opacityState, vmPrimitiveIndex); diff --git a/omm-sdk/shaders/omm_global_cb.hlsli b/omm-sdk/shaders/omm_global_cb.hlsli index 89ec58d..3fbd325 100644 --- a/omm-sdk/shaders/omm_global_cb.hlsli +++ b/omm-sdk/shaders/omm_global_cb.hlsli @@ -32,13 +32,13 @@ OMM_CONSTANTS_START(GlobalConstants) \ OMM_CONSTANT(uint, TexCoordHashTableEntryCount) \ \ OMM_CONSTANT(float, DynamicSubdivisionScale) \ - OMM_CONSTANT(uint, TexCoord1Format) \ - OMM_CONSTANT(uint, TexCoord1Offset) \ - OMM_CONSTANT(uint, TexCoord1Stride) \ + OMM_CONSTANT(uint, TexCoordFormat) \ + OMM_CONSTANT(uint, TexCoordOffset) \ + OMM_CONSTANT(uint, TexCoordStride) \ \ OMM_CONSTANT(float, AlphaCutoff) \ - OMM_CONSTANT(uint, AlphaCutoffLE) \ - OMM_CONSTANT(uint, AlphaCutoffGT) \ + OMM_CONSTANT(uint, AlphaCutoffLessEqual) \ + OMM_CONSTANT(uint, AlphaCutoffGreater) \ OMM_CONSTANT(uint, AlphaTextureChannel) \ \ OMM_CONSTANT(uint, FilterType) /* TextureFilterMode */ \ diff --git a/omm-sdk/shaders/omm_init_buffers_cs.cs.resources.hlsli b/omm-sdk/shaders/omm_init_buffers_cs.cs.resources.hlsli index a871a41..dcb7c13 100644 --- a/omm-sdk/shaders/omm_init_buffers_cs.cs.resources.hlsli +++ b/omm-sdk/shaders/omm_init_buffers_cs.cs.resources.hlsli @@ -11,9 +11,9 @@ license agreement from NVIDIA CORPORATION is strictly prohibited. #define OMM_DECLARE_INPUT_RESOURCES #define OMM_DECLARE_OUTPUT_RESOURCES \ - OMM_OUTPUT_RESOURCE( RWByteAddressBuffer, u_buffer0, u, 0 ) \ + OMM_OUTPUT_RESOURCE( RWByteAddressBuffer, u_heap0, u, 0 ) \ OMM_OUTPUT_RESOURCE( RWByteAddressBuffer, u_ommDescArrayHistogramBuffer, u, 1 ) \ OMM_OUTPUT_RESOURCE( RWByteAddressBuffer, u_ommIndexHistogramBuffer, u, 2 ) #define OMM_DECLARE_SUBRESOURCES \ - OMM_SUBRESOURCE(RWByteAddressBuffer, IEBakeCsBuffer, u_buffer0) + OMM_SUBRESOURCE(RWByteAddressBuffer, IEBakeCsBuffer, u_heap0) diff --git a/omm-sdk/shaders/omm_post_build_info.cs.resources.hlsli b/omm-sdk/shaders/omm_post_build_info.cs.resources.hlsli index 806a946..b965e35 100644 --- a/omm-sdk/shaders/omm_post_build_info.cs.resources.hlsli +++ b/omm-sdk/shaders/omm_post_build_info.cs.resources.hlsli @@ -9,7 +9,7 @@ license agreement from NVIDIA CORPORATION is strictly prohibited. */ #define OMM_DECLARE_INPUT_RESOURCES \ - OMM_OUTPUT_RESOURCE( ByteAddressBuffer, u_heap0, t, 0 ) + OMM_INPUT_RESOURCE( ByteAddressBuffer, u_heap0, t, 0 ) #define OMM_DECLARE_OUTPUT_RESOURCES \ OMM_OUTPUT_RESOURCE( RWByteAddressBuffer, u_postBuildInfo, u, 0 ) diff --git a/omm-sdk/shaders/omm_rasterize_cs.hlsli b/omm-sdk/shaders/omm_rasterize_cs.hlsli index 81f6782..db4a535 100644 --- a/omm-sdk/shaders/omm_rasterize_cs.hlsli +++ b/omm-sdk/shaders/omm_rasterize_cs.hlsli @@ -444,7 +444,7 @@ void main(uint3 tid : SV_DispatchThreadID) } } - const OpacityState opacityState = GetOpacityState(isOpaque, isTransparent, g_GlobalConstants.AlphaCutoffGT, g_GlobalConstants.AlphaCutoffLE, ommFormat); + const OpacityState opacityState = GetOpacityState(isOpaque, isTransparent, g_GlobalConstants.AlphaCutoffGreater, g_GlobalConstants.AlphaCutoffLessEqual, ommFormat); StoreMacroTriangleState(opacityState, vmPrimitiveIndex); diff --git a/omm-sdk/shaders/omm_rasterize_debug.ps.hlsl b/omm-sdk/shaders/omm_rasterize_debug.ps.hlsl index 5417044..7278c61 100644 --- a/omm-sdk/shaders/omm_rasterize_debug.ps.hlsl +++ b/omm-sdk/shaders/omm_rasterize_debug.ps.hlsl @@ -36,7 +36,7 @@ void main( const uint numOpaque = OMM_SUBRESOURCE_LOAD(BakeResultBuffer, microTriOffset); const uint numTrans = OMM_SUBRESOURCE_LOAD(BakeResultBuffer, microTriOffset + 4); - const OpacityState state = GetOpacityState(numOpaque, numTrans, g_GlobalConstants.AlphaCutoffGT, g_GlobalConstants.AlphaCutoffLE, OMMFormat::OC1_4); + const OpacityState state = GetOpacityState(numOpaque, numTrans, g_GlobalConstants.AlphaCutoffGreater, g_GlobalConstants.AlphaCutoffLessEqual, OMMFormat::OC1_4); const float3 debugColor = GetDebugColorForState(state); const float2 texCoord = raster::PS_SV_Position_to_TexCoord(i_svPosition); diff --git a/omm-sdk/src/bake.cpp b/omm-sdk/src/bake.cpp index bd02339..27714e3 100644 --- a/omm-sdk/src/bake.cpp +++ b/omm-sdk/src/bake.cpp @@ -9,10 +9,12 @@ license agreement from NVIDIA CORPORATION is strictly prohibited. */ #include "omm.h" +#include "omm_handle.h" #include "bake_cpu_impl.h" #include "bake_gpu_impl.h" #include "debug_impl.h" #include "texture_impl.h" +#include "serialize_impl.h" #include "version.h" #include @@ -22,27 +24,13 @@ using namespace omm; namespace { -static const ommLibraryDesc g_vmbakeLibraryDesc = +static const ommLibraryDesc g_ommbakeLibraryDesc = { VERSION_MAJOR, VERSION_MINOR, VERSION_BUILD }; -ommBakerType GetBakerType(ommBaker baker) { - return static_cast(baker & 0x7); -} - -template -T* GetBakerImpl(ommBaker baker) { - return reinterpret_cast(baker & 0xFFFFFFFFFFFFFFF8); -} - -template -ommBaker CreateHandle(ommBakerType type, T * impl) { - return (uintptr_t)(impl) | (uintptr_t)type; -} - } // namespace OMM_API ommLibraryDesc OMM_CALL ommGetLibraryDesc() @@ -50,7 +38,7 @@ OMM_API ommLibraryDesc OMM_CALL ommGetLibraryDesc() static_assert(VERSION_MAJOR == OMM_VERSION_MAJOR); static_assert(VERSION_MINOR == OMM_VERSION_MINOR); static_assert(VERSION_BUILD == OMM_VERSION_BUILD); - return g_vmbakeLibraryDesc; + return g_ommbakeLibraryDesc; } OMM_API ommResult OMM_CALL ommCpuCreateTexture(ommBaker baker, const ommCpuTextureDesc* desc, ommCpuTexture* outTexture) @@ -58,11 +46,11 @@ OMM_API ommResult OMM_CALL ommCpuCreateTexture(ommBaker baker, const ommCpuTextu if (baker == 0) return ommResult_INVALID_ARGUMENT; - Cpu::BakerImpl* impl = GetBakerImpl(baker); + Cpu::BakerImpl* impl = GetHandleImpl(baker); if (desc == 0) return impl->GetLog().InvalidArg("texture desc was not set"); - if (GetBakerType(baker) != ommBakerType_CPU) + if (GetHandleType(baker) != HandleType::CpuBaker) return impl->GetLog().InvalidArg("Baker was not created as the right type"); StdAllocator& memoryAllocator = (*impl).GetStdAllocator(); @@ -72,7 +60,7 @@ OMM_API ommResult OMM_CALL ommCpuCreateTexture(ommBaker baker, const ommCpuTextu if (result == ommResult_SUCCESS) { - *outTexture = (ommCpuTexture)implementation; + *outTexture = CreateHandle(implementation); return ommResult_SUCCESS; } @@ -85,14 +73,16 @@ OMM_API ommResult OMM_CALL ommCpuDestroyTexture(ommBaker baker, ommCpuTexture te if (texture == 0) return ommResult_INVALID_ARGUMENT; - Cpu::BakerImpl* impl = GetBakerImpl(baker); + Cpu::BakerImpl* impl = GetHandleImpl(baker); - if (GetBakerType(baker) != ommBakerType_CPU) + if (GetHandleType(baker) != HandleType::CpuBaker) return impl->GetLog().InvalidArg("Baker was not created as the right type"); StdAllocator& memoryAllocator = (*impl).GetStdAllocator(); - Deallocate(memoryAllocator, (TextureImpl*)texture); + TextureImpl* textureImpl = GetHandleImpl(texture); + + Deallocate(memoryAllocator, textureImpl); return ommResult_SUCCESS; } @@ -102,11 +92,11 @@ OMM_API ommResult OMM_CALL ommCpuBake(ommBaker baker, const ommCpuBakeInputDesc* if (baker == 0) return ommResult_INVALID_ARGUMENT; - Cpu::BakerImpl* impl = GetBakerImpl(baker); + Cpu::BakerImpl* impl = GetHandleImpl(baker); if (bakeInputDesc == 0) return impl->GetLog().InvalidArg("input desc was not set"); - if (GetBakerType(baker) != ommBakerType_CPU) + if (GetHandleType(baker) != HandleType::CpuBaker) return impl->GetLog().InvalidArg("Baker was not created as the right type"); return (*impl).BakeOpacityMicromap(*bakeInputDesc, bakeResult); @@ -117,7 +107,7 @@ OMM_API ommResult OMM_CALL ommCpuDestroyBakeResult(ommCpuBakeResult bakeResult) if (bakeResult == 0) return ommResult_INVALID_ARGUMENT; - StdAllocator& memoryAllocator = (*(omm::Cpu::BakeOutputImpl*)bakeResult).GetStdAllocator(); + const StdAllocator& memoryAllocator = (*(omm::Cpu::BakeOutputImpl*)bakeResult).GetStdAllocator(); Deallocate(memoryAllocator, (omm::Cpu::BakeOutputImpl*)bakeResult); return ommResult_SUCCESS; @@ -131,6 +121,123 @@ OMM_API ommResult OMM_CALL ommCpuGetBakeResultDesc(ommCpuBakeResult bakeResult, return (*(omm::Cpu::BakeOutputImpl*)bakeResult).GetBakeResultDesc(desc); } +OMM_API ommResult OMM_CALL ommCpuSerialize(ommBaker baker, const ommCpuDeserializedDesc& desc, ommCpuSerializedResult* outResult) +{ + if (baker == 0) + return ommResult_INVALID_ARGUMENT; + + if (outResult == nullptr) + return ommResult_INVALID_ARGUMENT; + + Cpu::BakerImpl* impl = GetHandleImpl(baker); + + if (GetHandleType(baker) != HandleType::CpuBaker) + return impl->GetLog().InvalidArg("Baker was not created as the right type"); + + StdAllocator& memoryAllocator = (*impl).GetStdAllocator(); + + omm::Cpu::SerializeResultImpl* blobImpl = Allocate(memoryAllocator, memoryAllocator, impl->GetLog()); + + ommResult res = blobImpl->Serialize(desc); + + if (res == ommResult_SUCCESS) + { + *outResult = CreateHandle(blobImpl); + } + else + { + Deallocate(memoryAllocator, blobImpl); + *outResult = (ommCpuSerializedResult)nullptr; + } + + return res; +} + +OMM_API ommResult ommCpuGetSerializedResultDesc(ommCpuSerializedResult result, const ommCpuBlobDesc** desc) +{ + if (result == 0) + return ommResult_INVALID_ARGUMENT; + + if (desc == nullptr) + return ommResult_INVALID_ARGUMENT; + + omm::Cpu::SerializeResultImpl* impl = GetHandleImpl(result); + *desc = impl->GetDesc(); + return ommResult_SUCCESS; +} + +OMM_API ommResult ommCpuDestroySerializedResult(ommCpuSerializedResult result) +{ + if (result == 0) + return ommResult_INVALID_ARGUMENT; + if (!CheckHandle(result)) + return ommResult_INVALID_ARGUMENT; + + omm::Cpu::SerializeResultImpl* impl = GetHandleImpl(result); + const StdAllocator& memoryAllocator = (*impl).GetStdAllocator(); + Deallocate(memoryAllocator, impl); + return ommResult_SUCCESS; +} + +OMM_API ommResult ommCpuDeserialize(ommBaker baker, const ommCpuBlobDesc& desc, ommCpuDeserializedResult* outResult) +{ + if (baker == 0) + return ommResult_INVALID_ARGUMENT; + + Cpu::BakerImpl* impl = GetHandleImpl(baker); + + if (GetHandleType(baker) != HandleType::CpuBaker) + return impl->GetLog().InvalidArg("Baker was not created as the right type"); + + StdAllocator& memoryAllocator = (*impl).GetStdAllocator(); + + omm::Cpu::DeserializedResultImpl* desImpl = Allocate(memoryAllocator, memoryAllocator, impl->GetLog()); + + ommResult res = desImpl->Deserialize(desc); + + if (res == ommResult_SUCCESS) + { + *outResult = CreateHandle(desImpl); + } + else + { + Deallocate(memoryAllocator, desImpl); + *outResult = (ommCpuDeserializedResult)nullptr; + } + + return res; +} + +OMM_API ommResult ommCpuGetDeserializedDesc(ommCpuDeserializedResult result, const ommCpuDeserializedDesc** desc) +{ + if (result == 0) + return ommResult_INVALID_ARGUMENT; + if (!CheckHandle(result)) + return ommResult_INVALID_ARGUMENT; + if (desc == nullptr) + return ommResult_INVALID_ARGUMENT; + + omm::Cpu::DeserializedResultImpl* desImpl = GetHandleImpl(result); + + *desc = desImpl->GetDesc(); + + return ommResult_SUCCESS; +} + +OMM_API ommResult ommCpuDestroyDeserializedResult(ommCpuDeserializedResult result) +{ + if (result == 0) + return ommResult_INVALID_ARGUMENT; + if (!CheckHandle(result)) + return ommResult_INVALID_ARGUMENT; + + omm::Cpu::DeserializedResultImpl* impl = GetHandleImpl(result); + + const StdAllocator& memoryAllocator = (*impl).GetStdAllocator(); + Deallocate(memoryAllocator, impl); + return ommResult_SUCCESS; +} + OMM_API ommResult OMM_CALL ommGpuGetStaticResourceData(ommGpuResourceType resource, uint8_t* data, size_t* outByteSize) { return Gpu::OmmStaticBuffers::GetStaticResourceData(resource, data, outByteSize); @@ -142,11 +249,11 @@ OMM_API ommResult OMM_CALL ommGpuCreatePipeline(ommBaker baker, const ommGpuPipe if (baker == 0) return ommResult_INVALID_ARGUMENT; - Gpu::BakerImpl* bakePtr = GetBakerImpl(baker); + Gpu::BakerImpl* bakePtr = GetHandleImpl(baker); if (config == 0) return bakePtr->GetLog().InvalidArg("[Invalid Arg] - pipeline config desc must be provided"); - if (GetBakerType(baker) != ommBakerType_GPU) + if (GetHandleType(baker) != HandleType::GpuBaker) return bakePtr->GetLog().InvalidArg("[Invalid Arg] - invalid baker type"); return bakePtr->CreatePipeline(*config, outPipeline); } @@ -155,7 +262,7 @@ OMM_API ommResult OMM_CALL ommGpuGetPipelineDesc(ommGpuPipeline pipeline, const { if (pipeline == 0) return ommResult_INVALID_ARGUMENT; - Gpu::PipelineImpl* impl = (Gpu::PipelineImpl*)(pipeline); + Gpu::PipelineImpl* impl = GetHandleImpl(pipeline); return impl->GetPipelineDesc(outPipelineDesc); } @@ -165,9 +272,9 @@ OMM_API ommResult OMM_CALL ommGpuDestroyPipeline(ommBaker baker, ommGpuPipeline return ommResult_INVALID_ARGUMENT; if (baker == 0) return ommResult_INVALID_ARGUMENT; - if (GetBakerType(baker) != ommBakerType_GPU) + if (GetHandleType(baker) != HandleType::GpuBaker) return ommResult_INVALID_ARGUMENT; - Gpu::BakerImpl* bakePtr = GetBakerImpl(baker); + Gpu::BakerImpl* bakePtr = GetHandleImpl(baker); return bakePtr->DestroyPipeline(pipeline); } @@ -177,7 +284,7 @@ OMM_API ommResult OMM_CALL ommGpuGetPreDispatchInfo(ommGpuPipeline pipeline, con return ommResult_INVALID_ARGUMENT; if (config == 0) return ommResult_INVALID_ARGUMENT; - Gpu::PipelineImpl* impl = (Gpu::PipelineImpl*)(pipeline); + Gpu::PipelineImpl* impl = GetHandleImpl(pipeline); return impl->GetPreDispatchInfo(*config, outPreBuildInfo); } @@ -187,7 +294,7 @@ OMM_API ommResult OMM_CALL ommGpuDispatch(ommGpuPipeline pipeline, const ommGpuD return ommResult_INVALID_ARGUMENT; if (dispatchConfig == 0) return ommResult_INVALID_ARGUMENT; - Gpu::PipelineImpl* impl = (Gpu::PipelineImpl*)(pipeline); + Gpu::PipelineImpl* impl = GetHandleImpl(pipeline); return impl->GetDispatchDesc(*dispatchConfig, outDispatchDesc); } @@ -199,15 +306,15 @@ OMM_API ommResult OMM_CALL ommDebugSaveAsImages(ommBaker baker, const ommCpuBake return ommResult_INVALID_ARGUMENT; if (desc == 0) return ommResult_INVALID_ARGUMENT; - if (GetBakerType(baker) == ommBakerType_CPU) + if (GetHandleType(baker) == HandleType::CpuBaker) { - Cpu::BakerImpl* impl = GetBakerImpl(baker); + Cpu::BakerImpl* impl = GetHandleImpl(baker); StdAllocator& memoryAllocator = (*impl).GetStdAllocator(); return SaveAsImagesImpl(memoryAllocator, *bakeInputDesc, res, *desc); } - else if (GetBakerType(baker) == ommBakerType_GPU) + else if (GetHandleType(baker) == HandleType::GpuBaker) { - Gpu::BakerImpl* impl = GetBakerImpl(baker); + Gpu::BakerImpl* impl = GetHandleImpl(baker); StdAllocator& memoryAllocator = (*impl).GetStdAllocator(); return SaveAsImagesImpl(memoryAllocator, *bakeInputDesc, res, *desc); } @@ -220,15 +327,15 @@ OMM_API ommResult OMM_CALL ommDebugGetStats(ommBaker baker, const ommCpuBakeResu if (baker == 0) return ommResult_INVALID_ARGUMENT; - if (GetBakerType(baker) == ommBakerType_CPU) + if (GetHandleType(baker) == HandleType::CpuBaker) { - Cpu::BakerImpl* impl = GetBakerImpl(baker); + Cpu::BakerImpl* impl = GetHandleImpl(baker); StdAllocator& memoryAllocator = (*impl).GetStdAllocator(); return GetStatsImpl(memoryAllocator, res, out); } - else if (GetBakerType(baker) == ommBakerType_GPU) + else if (GetHandleType(baker) == HandleType::GpuBaker) { - Gpu::BakerImpl* impl = GetBakerImpl(baker); + Gpu::BakerImpl* impl = GetHandleImpl(baker); StdAllocator& memoryAllocator = (*impl).GetStdAllocator(); return GetStatsImpl(memoryAllocator, res, out); } @@ -236,6 +343,28 @@ OMM_API ommResult OMM_CALL ommDebugGetStats(ommBaker baker, const ommCpuBakeResu return ommResult_INVALID_ARGUMENT; } +OMM_API ommResult OMM_CALL ommDebugSaveBinaryToDisk(ommBaker baker, const ommCpuBlobDesc& data, const char* path) +{ + if (baker == 0) + return ommResult_INVALID_ARGUMENT; + if (path == 0) + return ommResult_INVALID_ARGUMENT; + if (GetHandleType(baker) == HandleType::CpuBaker) + { + Cpu::BakerImpl* impl = GetHandleImpl(baker); + const Logger& log = (*impl).GetLog(); + return SaveBinaryToDiskImpl(log, data, path); + } + else if (GetHandleType(baker) == HandleType::GpuBaker) + { + Gpu::BakerImpl* impl = GetHandleImpl(baker); + const Logger& log = (*impl).GetLog(); + return SaveBinaryToDiskImpl(log, data, path); + } + else + return ommResult_INVALID_ARGUMENT; +} + OMM_API ommResult OMM_CALL ommCreateBaker(const ommBakerCreationDesc* desc, ommBaker* baker) { if (desc == 0) @@ -259,7 +388,7 @@ OMM_API ommResult OMM_CALL ommCreateBaker(const ommBakerCreationDesc* desc, ommB if (result == ommResult_SUCCESS) { - *baker = CreateHandle(desc->type, implementation); + *baker = CreateHandle(implementation); return ommResult_SUCCESS; } @@ -272,7 +401,7 @@ OMM_API ommResult OMM_CALL ommCreateBaker(const ommBakerCreationDesc* desc, ommB if (result == ommResult_SUCCESS) { - *baker = CreateHandle(desc->type, implementation); + *baker = CreateHandle(implementation); return ommResult_SUCCESS; } @@ -290,17 +419,17 @@ OMM_API ommResult OMM_CALL ommDestroyBaker(ommBaker baker) if (baker == 0) return ommResult_INVALID_ARGUMENT; - const ommBakerType type = GetBakerType(baker); - if (type == ommBakerType_CPU) + const HandleType type = GetHandleType(baker); + if (type == HandleType::CpuBaker) { - Cpu::BakerImpl* impl = GetBakerImpl(baker); + Cpu::BakerImpl* impl = GetHandleImpl(baker); StdAllocator& memoryAllocator = (*impl).GetStdAllocator(); Deallocate(memoryAllocator, impl); return ommResult_SUCCESS; } - else if (type == ommBakerType_GPU) + else if (type == HandleType::GpuBaker) { - Gpu::BakerImpl* bakePtr = GetBakerImpl(baker); + Gpu::BakerImpl* bakePtr = GetHandleImpl(baker); StdAllocator& memoryAllocator = (*bakePtr).GetStdAllocator(); Deallocate(memoryAllocator, bakePtr); return ommResult_SUCCESS; diff --git a/omm-sdk/src/bake_cpu_impl.cpp b/omm-sdk/src/bake_cpu_impl.cpp index d1b8a2f..cc560fe 100644 --- a/omm-sdk/src/bake_cpu_impl.cpp +++ b/omm-sdk/src/bake_cpu_impl.cpp @@ -188,6 +188,8 @@ namespace Cpu if (desc.texture == 0) return m_log.InvalidArg("[Invalid Argument] - texture is not set"); + if (!GetCheckedHandleImpl(desc.texture)) + return m_log.InvalidArg("[Invalid Argument] - desc.texture is of incorrect type"); if (desc.alphaMode == ommAlphaMode_MAX_NUM) return m_log.InvalidArg("[Invalid Argument] - alphaMode is not set"); if (desc.runtimeSamplerDesc.addressingMode == ommTextureAddressMode_MAX_NUM) @@ -217,7 +219,7 @@ namespace Cpu if (options.enableWorkloadValidation && !m_log.HasLogger()) return m_log.InvalidArg("[Invalid Argument] - EnableWorkloadValidation is set but not message callback was provided"); // this works more as documentation since it won't be logged - if (TextureImpl* texture = ((TextureImpl*)desc.texture)) + if (TextureImpl* texture = GetHandleImpl(desc.texture)) { if (texture->HasAlphaCutoff() && texture->GetAlphaCutoff() != desc.alphaCutoff) { @@ -225,14 +227,14 @@ namespace Cpu } } - if (!IsCompatible(desc.alphaCutoffGT, desc.format)) + if (!IsCompatible(desc.alphaCutoffGreater, desc.format)) { - return m_log.InvalidArgf("[Invalid Argument] - alphaCutoffGT=%s is not compatible with %s", GetOpacityStateAsString(desc.alphaCutoffGT), GetFormatAsString(desc.format)); + return m_log.InvalidArgf("[Invalid Argument] - alphaCutoffGreater=%s is not compatible with %s", GetOpacityStateAsString(desc.alphaCutoffGreater), GetFormatAsString(desc.format)); } - if (!IsCompatible(desc.alphaCutoffLE, desc.format)) + if (!IsCompatible(desc.alphaCutoffLessEqual, desc.format)) { - return m_log.InvalidArgf("[Invalid Argument] - alphaCutoffLE=%s is not compatible with %s", GetOpacityStateAsString(desc.alphaCutoffLE), GetFormatAsString(desc.format)); + return m_log.InvalidArgf("[Invalid Argument] - alphaCutoffLessEqual=%s is not compatible with %s", GetOpacityStateAsString(desc.alphaCutoffLessEqual), GetFormatAsString(desc.format)); } return ommResult_SUCCESS; @@ -244,7 +246,7 @@ namespace Cpu } ommResult BakeOutputImpl::InvokeDispatch(const ommCpuBakeInputDesc& desc) { - TextureImpl* texture = ((TextureImpl*)desc.texture); + TextureImpl* texture = GetHandleImpl(desc.texture); auto it = bakeDispatchTable.find(std::make_tuple(texture->GetTextureFormat(), texture->GetTilingMode(), desc.runtimeSamplerDesc.addressingMode, desc.runtimeSamplerDesc.filter)); if (it == bakeDispatchTable.end()) return ommResult_FAILURE; @@ -346,7 +348,7 @@ namespace Cpu { public: OmmArrayDataVector() = delete; - OmmArrayDataVector(StdAllocator& stdAllocator, ommFormat format, uint32_t _subdivisionLevel) + OmmArrayDataVector(const StdAllocator& stdAllocator, ommFormat format, uint32_t _subdivisionLevel) : OmmArrayDataView(format, nullptr, nullptr, 0) , data(stdAllocator.GetInterface()) , data3state(stdAllocator.GetInterface()) @@ -379,7 +381,7 @@ namespace Cpu OmmWorkItem() = delete; - OmmWorkItem(StdAllocator& stdAllocator, ommFormat _vmFormat, uint32_t _subdivisionLevel, uint32_t primitiveIndex, const Triangle& _uvTri) + OmmWorkItem(const StdAllocator& stdAllocator, ommFormat _vmFormat, uint32_t _subdivisionLevel, uint32_t primitiveIndex, const Triangle& _uvTri) : primitiveIndices(stdAllocator) , subdivisionLevel(_subdivisionLevel) , vmFormat(_vmFormat) @@ -486,10 +488,10 @@ namespace Cpu namespace impl { static ommResult SetupWorkItems( - StdAllocator& allocator, const Logger& log, const ommCpuBakeInputDesc& desc, const Options& options, + const StdAllocator& allocator, const Logger& log, const ommCpuBakeInputDesc& desc, const Options& options, vector& vmWorkItems) { - const TextureImpl* texture = ((const TextureImpl*)desc.texture); + const TextureImpl* texture = GetHandleImpl(desc.texture); const int32_t triangleCount = desc.indexCount / 3u; @@ -554,14 +556,9 @@ namespace Cpu return ommResult_SUCCESS; } - static ommResult ValidateWorkloadSize( - StdAllocator& allocator, Logger log, const ommCpuBakeInputDesc& desc, const Options& options, vector& vmWorkItems) + static uint64_t ComputeWorkloadSize(const ommCpuBakeInputDesc& desc, vector& vmWorkItems) { - // Check if the baking will complete in "finite" amount of time... - if (!options.enableWorkloadValidation) - return ommResult_SUCCESS; - - const TextureImpl* texture = ((const TextureImpl*)desc.texture); + const TextureImpl* texture = GetHandleImpl(desc.texture); // Approximate the workload size. // The workload metric is the accumulated count of the number of texels in total that needs to be processed. @@ -576,13 +573,37 @@ namespace Cpu workloadSize += uint64_t(aabb.x * aabb.y); } - const uint64_t kMaxWorkloadSize = 1 << 27; // 128 * 1024x1024 texels. - if (workloadSize > kMaxWorkloadSize) + return workloadSize; + } + + static ommResult ValidateWorkloadSize( + const StdAllocator& allocator, Logger log, const ommCpuBakeInputDesc& desc, const Options& options, vector& ommWorkItems) + { + const bool limitWorkloadSize = desc.maxWorkloadSize != 0xFFFFFFFFFFFFFFFF; + + if (!options.enableWorkloadValidation && !limitWorkloadSize) + return ommResult_SUCCESS; + + uint64_t workloadSize = ComputeWorkloadSize(desc, ommWorkItems); + + if (limitWorkloadSize) { - const uint64_t num1Ktextures = workloadSize >> (20ull); // divide by 1024x1024 + if (workloadSize > desc.maxWorkloadSize) + { + return ommResult_WORKLOAD_TOO_BIG; + } + } + + if (options.enableWorkloadValidation) + { + const uint64_t warnSize = 1ull << 27ull; // 128 * 1024x1024 texels. + if (workloadSize > warnSize) + { + const uint64_t num1Ktextures = workloadSize >> (20ull); // divide by 1024x1024 - log.PerfWarnf("[Perf Warning] - The workload consists of %lld work items (number of texels to classify), which corresponds to roughly %lld 1024x1024 textures." - " This is unusually large and may result in long bake times.", workloadSize, num1Ktextures); + log.PerfWarnf("[Perf Warning] - The workload consists of %lld work items (number of texels to classify), which corresponds to roughly %lld 1024x1024 textures." + " This is unusually large and may result in long bake times.", workloadSize, num1Ktextures); + } } return ommResult_SUCCESS; @@ -594,7 +615,7 @@ namespace Cpu if (options.enableAABBTesting && !options.disableLevelLineIntersection) return log.InvalidArg("[Invalid Arg] - EnableAABBTesting can't be used without also setting DisableLevelLineIntersection"); - const TextureImpl* texture = ((const TextureImpl*)desc.texture); + const TextureImpl* texture = GetHandleImpl(desc.texture); if (!texture->HasSAT()) return ommResult_SUCCESS; @@ -667,12 +688,12 @@ namespace Cpu if (sa == 0) { // (Less than or equal to alpha threshold) - workItem.vmStates.SetState(uTriIt, desc.alphaCutoffLE); + workItem.vmStates.SetState(uTriIt, desc.alphaCutoffLessEqual); } else if (sa == area) { // (Greater than alpha threshold) - workItem.vmStates.SetState(uTriIt, desc.alphaCutoffGT); + workItem.vmStates.SetState(uTriIt, desc.alphaCutoffGreater); } } } @@ -692,7 +713,7 @@ namespace Cpu if (options.disableFineClassification) return ommResult_SUCCESS; - const TextureImpl* texture = ((const TextureImpl*)desc.texture); + const TextureImpl* texture = GetHandleImpl(desc.texture); // 3. Process the queue of unique triangles... { @@ -752,12 +773,12 @@ namespace Cpu RasterizeConservativeSerialWithOffsetCoverage(subTri, rasterSize, pixelOffset, kernel, ¶ms); OMM_ASSERT(vmCoverage.numAboveAlpha != 0 || vmCoverage.numBelowAlpha != 0); - const ommOpacityState state = GetStateFromCoverage(desc.format, desc.unknownStatePromotion, desc.alphaCutoffGT, desc.alphaCutoffLE, vmCoverage); + const ommOpacityState state = GetStateFromCoverage(desc.format, desc.unknownStatePromotion, desc.alphaCutoffGreater, desc.alphaCutoffLessEqual, vmCoverage); if (IsUnknown(state)) break; } - const ommOpacityState state = GetStateFromCoverage(desc.format, desc.unknownStatePromotion, desc.alphaCutoffGT, desc.alphaCutoffLE, vmCoverage); + const ommOpacityState state = GetStateFromCoverage(desc.format, desc.unknownStatePromotion, desc.alphaCutoffGreater, desc.alphaCutoffLessEqual, vmCoverage); workItem.vmStates.SetState(uTriIt, state); } else if (options.enableAABBTesting) @@ -783,7 +804,7 @@ namespace Cpu OMM_ASSERT(vmCoverage.numAboveAlpha != 0 || vmCoverage.numBelowAlpha != 0); - const ommOpacityState state = GetStateFromCoverage(desc.format, desc.unknownStatePromotion, desc.alphaCutoffGT, desc.alphaCutoffLE, vmCoverage); + const ommOpacityState state = GetStateFromCoverage(desc.format, desc.unknownStatePromotion, desc.alphaCutoffGreater, desc.alphaCutoffLessEqual, vmCoverage); workItem.vmStates.SetState(uTriIt, state); } else @@ -807,7 +828,7 @@ namespace Cpu OMM_ASSERT(vmCoverage.numBelowAlpha != 0 || vmCoverage.numAboveAlpha != 0); - const ommOpacityState state = GetStateFromCoverage(desc.format, desc.unknownStatePromotion, desc.alphaCutoffGT, desc.alphaCutoffLE, vmCoverage); + const ommOpacityState state = GetStateFromCoverage(desc.format, desc.unknownStatePromotion, desc.alphaCutoffGreater, desc.alphaCutoffLessEqual, vmCoverage); workItem.vmStates.SetState(uTriIt, state); } @@ -858,11 +879,11 @@ namespace Cpu RasterizeConservativeSerial(subTri, rasterSize, kernel, ¶ms); OMM_ASSERT(vmCoverage.numAboveAlpha != 0 || vmCoverage.numBelowAlpha != 0); - const ommOpacityState state = GetStateFromCoverage(desc.format, desc.unknownStatePromotion, desc.alphaCutoffGT, desc.alphaCutoffLE, vmCoverage); + const ommOpacityState state = GetStateFromCoverage(desc.format, desc.unknownStatePromotion, desc.alphaCutoffGreater, desc.alphaCutoffLessEqual, vmCoverage); if (IsUnknown(state)) break; } - const ommOpacityState state = GetStateFromCoverage(desc.format, desc.unknownStatePromotion, desc.alphaCutoffGT, desc.alphaCutoffLE, vmCoverage); + const ommOpacityState state = GetStateFromCoverage(desc.format, desc.unknownStatePromotion, desc.alphaCutoffGreater, desc.alphaCutoffLessEqual, vmCoverage); workItem.vmStates.SetState(uTriIt, state); } } @@ -873,7 +894,7 @@ namespace Cpu return ommResult_SUCCESS; } - static ommResult DeduplicateExact(StdAllocator& allocator, const Options& options, vector& vmWorkItems) + static ommResult DeduplicateExact(const StdAllocator& allocator, const Options& options, vector& vmWorkItems) { if (options.disableDuplicateDetection) return ommResult_SUCCESS; @@ -976,7 +997,7 @@ namespace Cpu return ommResult_SUCCESS; } - static ommResult DeduplicateSimilarLSH(StdAllocator& allocator, const Options& options, vector& vmWorkItems, uint32_t iterations) + static ommResult DeduplicateSimilarLSH(const StdAllocator& allocator, const Options& options, vector& vmWorkItems, uint32_t iterations) { if (options.disableDuplicateDetection) return ommResult_SUCCESS; @@ -1004,7 +1025,7 @@ namespace Cpu vector bitIndices; // random bit indices vector workItemHashes; hash_map> layerHashToWorkItem; - HashTable(StdAllocator& allocator) :bitIndices(allocator), workItemHashes(allocator), layerHashToWorkItem(allocator) + HashTable(const StdAllocator& allocator) :bitIndices(allocator), workItemHashes(allocator), layerHashToWorkItem(allocator) { } }; @@ -1196,7 +1217,7 @@ namespace Cpu return ommResult_SUCCESS; } - static ommResult DeduplicateSimilarBruteForce(StdAllocator& allocator, const Options& options, vector& vmWorkItems) + static ommResult DeduplicateSimilarBruteForce(const StdAllocator& allocator, const Options& options, vector& vmWorkItems) { if (options.disableDuplicateDetection) return ommResult_SUCCESS; @@ -1330,7 +1351,7 @@ namespace Cpu return ommResult_SUCCESS; } - static ommResult MicromapSpatialSort(StdAllocator& allocator, const Options& options, const vector& vmWorkItems, + static ommResult MicromapSpatialSort(const StdAllocator& allocator, const Options& options, const vector& vmWorkItems, vector>& sortKeys) { // The VMs should be sorted to respect the following rules: @@ -1380,7 +1401,7 @@ namespace Cpu } static ommResult Serialize( - StdAllocator& allocator, + const StdAllocator& allocator, const ommCpuBakeInputDesc& desc, const Options& options, vector& vmWorkItems, const VisibilityMapUsageHistogram& ommArrayHistogram, const VisibilityMapUsageHistogram& ommIndexHistogram, const vector>& sortKeys, BakeResultImpl& res) diff --git a/omm-sdk/src/bake_cpu_impl.h b/omm-sdk/src/bake_cpu_impl.h index c0ba527..90f6928 100644 --- a/omm-sdk/src/bake_cpu_impl.h +++ b/omm-sdk/src/bake_cpu_impl.h @@ -11,6 +11,7 @@ license agreement from NVIDIA CORPORATION is strictly prohibited. #pragma once #include "omm.h" +#include "omm_handle.h" #include "defines.h" #include "std_containers.h" #include "texture_impl.h" @@ -32,6 +33,9 @@ namespace Cpu { // Internal public: + + static inline constexpr HandleType kHandleType = HandleType::CpuBaker; + inline BakerImpl(const StdAllocator& stdAllocator) : m_stdAllocator(stdAllocator) {} @@ -94,7 +98,7 @@ namespace Cpu BakeOutputImpl(const StdAllocator& stdAllocator, const Logger& log); ~BakeOutputImpl(); - inline StdAllocator& GetStdAllocator() + inline const StdAllocator& GetStdAllocator() const { return m_stdAllocator; } diff --git a/omm-sdk/src/bake_gpu_impl.cpp b/omm-sdk/src/bake_gpu_impl.cpp index e834ab3..338337b 100644 --- a/omm-sdk/src/bake_gpu_impl.cpp +++ b/omm-sdk/src/bake_gpu_impl.cpp @@ -272,10 +272,10 @@ ommResult PipelineImpl::Validate(const ommGpuDispatchConfigDesc& config) const if (!doBake && !doSetup) return m_log.InvalidArg("[Invalid Arg] - Either ommGpuBakeFlags_PerformBake or ommGpuBakeFlags_PerformSetup must be set"); - if (!IsCompatible(config.alphaCutoffGT, config.globalFormat)) - return m_log.InvalidArgf("[Invalid Argument] - alphaCutoffGT=%s is not compatible with %s", GetOpacityStateAsString(config.alphaCutoffGT), GetFormatAsString(config.globalFormat)); - if (!IsCompatible(config.alphaCutoffLE, config.globalFormat)) - return m_log.InvalidArgf("[Invalid Argument] - alphaCutoffLE=%s is not compatible with %s", GetOpacityStateAsString(config.alphaCutoffLE), GetFormatAsString(config.globalFormat)); + if (!IsCompatible(config.alphaCutoffGreater, config.globalFormat)) + return m_log.InvalidArgf("[Invalid Argument] - alphaCutoffGreater=%s is not compatible with %s", GetOpacityStateAsString(config.alphaCutoffGreater), GetFormatAsString(config.globalFormat)); + if (!IsCompatible(config.alphaCutoffLessEqual, config.globalFormat)) + return m_log.InvalidArgf("[Invalid Argument] - alphaCutoffLessEqual=%s is not compatible with %s", GetOpacityStateAsString(config.alphaCutoffLessEqual), GetFormatAsString(config.globalFormat)); return ommResult_SUCCESS; } @@ -734,12 +734,12 @@ ommResult PipelineImpl::InitGlobalConstants(const ommGpuDispatchConfigDesc& conf cbuffer.TexSize = float2(config.alphaTextureWidth, config.alphaTextureHeight); static_assert(sizeof(float2) == sizeof(float) * 2); cbuffer.InvTexSize = 1.f / cbuffer.TexSize; - cbuffer.TexCoord1Format = (uint32_t)config.texCoordFormat; - cbuffer.TexCoord1Offset = config.texCoordOffsetInBytes; - cbuffer.TexCoord1Stride = config.texCoordStrideInBytes == 0 ? GetTexCoordFormatSize(config.texCoordFormat) : config.texCoordStrideInBytes; + cbuffer.TexCoordFormat = (uint32_t)config.texCoordFormat; + cbuffer.TexCoordOffset = config.texCoordOffsetInBytes; + cbuffer.TexCoordStride = config.texCoordStrideInBytes == 0 ? GetTexCoordFormatSize(config.texCoordFormat) : config.texCoordStrideInBytes; cbuffer.AlphaCutoff = config.alphaCutoff; - cbuffer.AlphaCutoffGT = (uint32_t)config.alphaCutoffGT; - cbuffer.AlphaCutoffLE = (uint32_t)config.alphaCutoffLE; + cbuffer.AlphaCutoffGreater = (uint32_t)config.alphaCutoffGreater; + cbuffer.AlphaCutoffLessEqual = (uint32_t)config.alphaCutoffLessEqual; cbuffer.AlphaTextureChannel = config.alphaTextureChannel; cbuffer.FilterType = (uint32_t)config.runtimeSamplerDesc.filter; cbuffer.EnableLevelLine = (uint32_t)enableLevelLine; @@ -1279,7 +1279,7 @@ ommResult BakerImpl::CreatePipeline(const ommGpuPipelineConfigDesc& config, ommG StdAllocator& memoryAllocator = GetStdAllocator(); PipelineImpl* implementation = Allocate(memoryAllocator, memoryAllocator, GetLog()); RETURN_STATUS_IF_FAILED(implementation->Create(config)); - *outPipeline = (ommGpuPipeline)implementation; + *outPipeline = CreateHandle(implementation); return ommResult_SUCCESS; } @@ -1288,7 +1288,7 @@ ommResult BakerImpl::DestroyPipeline(ommGpuPipeline pipeline) if (pipeline == 0) return m_log.InvalidArg("[Invalid Arg] - pipeline is null"); - PipelineImpl* impl = (PipelineImpl*)pipeline; + PipelineImpl* impl = GetHandleImpl< PipelineImpl>(pipeline); StdAllocator& memoryAllocator = GetStdAllocator(); Deallocate(memoryAllocator, impl); return ommResult_SUCCESS; diff --git a/omm-sdk/src/bake_gpu_impl.h b/omm-sdk/src/bake_gpu_impl.h index dcf82d6..e1d0f72 100644 --- a/omm-sdk/src/bake_gpu_impl.h +++ b/omm-sdk/src/bake_gpu_impl.h @@ -11,6 +11,7 @@ license agreement from NVIDIA CORPORATION is strictly prohibited. #pragma once #include "omm.h" +#include "omm_handle.h" #include "std_containers.h" #include "shader_bindings.h" #include "std_allocator.h" @@ -909,6 +910,9 @@ namespace Gpu { // Internal public: + + static constexpr HandleType kHandleType = HandleType::Pipeline; + PipelineImpl(const StdAllocator& stdAllocator, const Logger& log) : m_stdAllocator(stdAllocator) , m_log(log) @@ -1057,6 +1061,8 @@ namespace Gpu { // Internal public: + static inline constexpr HandleType kHandleType = HandleType::GpuBaker; + inline BakerImpl(const StdAllocator& stdAllocator) : m_stdAllocator(stdAllocator) {} diff --git a/omm-sdk/src/debug_impl.cpp b/omm-sdk/src/debug_impl.cpp index f1d9de6..59b2c6f 100644 --- a/omm-sdk/src/debug_impl.cpp +++ b/omm-sdk/src/debug_impl.cpp @@ -142,7 +142,7 @@ namespace omm if (dumpDesc.detailedCutout && dumpDesc.oneFile) return ommResult_INVALID_ARGUMENT; - TextureImpl* texImpl = (TextureImpl*)desc.texture; + const TextureImpl* texImpl = GetHandleImpl(desc.texture); vector states(memoryAllocator); set dumpedOMMs(memoryAllocator); @@ -581,4 +581,22 @@ namespace omm *out = CollectStats(memoryAllocator, *resDesc); return ommResult_SUCCESS; } + + ommResult SaveBinaryToDiskImpl(const Logger& log, const ommCpuBlobDesc& data, const char* path) + { + std::ofstream outputFile(path, std::ios::binary); + + if (outputFile.is_open()) + { + outputFile.write(reinterpret_cast(data.data), data.size); + + outputFile.close(); + + return ommResult_SUCCESS; + } + else { + return log.ErrorArgf("Unable to save file %s", path); + } + } + } // namespace omm \ No newline at end of file diff --git a/omm-sdk/src/debug_impl.h b/omm-sdk/src/debug_impl.h index 9cbb01f..c869227 100644 --- a/omm-sdk/src/debug_impl.h +++ b/omm-sdk/src/debug_impl.h @@ -12,10 +12,13 @@ license agreement from NVIDIA CORPORATION is strictly prohibited. #include "omm.h" #include "std_allocator.h" +#include "log.h" namespace omm { OMM_API ommResult SaveAsImagesImpl(StdAllocator& memoryAllocator, const ommCpuBakeInputDesc& bakeInputDesc, const ommCpuBakeResultDesc* res, const ommDebugSaveImagesDesc& desc); OMM_API ommResult GetStatsImpl(StdAllocator& memoryAllocator, const ommCpuBakeResultDesc* res, ommDebugStats* out); + + OMM_API ommResult SaveBinaryToDiskImpl(const Logger& log, const ommCpuBlobDesc& data, const char* path); } diff --git a/omm-sdk/src/log.h b/omm-sdk/src/log.h index 13c29a0..4991221 100644 --- a/omm-sdk/src/log.h +++ b/omm-sdk/src/log.h @@ -47,6 +47,17 @@ namespace omm _Logf(ommMessageSeverity_PerfWarning, format, std::forward(args)...); } + void Error(const char* msg) const + { + _Log(ommMessageSeverity_Error, msg); + } + + template + void Errorf(const char* format, Args&&... args) const + { + _Logf(ommMessageSeverity_Error, format, std::forward(args)...); + } + void Fatal(const char* msg) const { _Log(ommMessageSeverity_Fatal, msg); @@ -73,6 +84,13 @@ namespace omm return ommResult_NOT_IMPLEMENTED; } + template + [[nodiscard]] ommResult ErrorArgf(const char* format, Args&&... args) const + { + RETURN_STATUS_IF_FAILED(_Logf(ommMessageSeverity_Error, format, std::forward(args)...)); + return ommResult_FAILURE; + } + private: void _Log(ommMessageSeverity severity, const char* msg) const diff --git a/omm-sdk/src/omm_handle.h b/omm-sdk/src/omm_handle.h new file mode 100644 index 0000000..9b1e817 --- /dev/null +++ b/omm-sdk/src/omm_handle.h @@ -0,0 +1,56 @@ +/* +Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. + +NVIDIA CORPORATION and its licensors retain all intellectual property +and proprietary rights in and to this software, related documentation +and any modifications thereto. Any use, reproduction, disclosure or +distribution of this software and related documentation without an express +license agreement from NVIDIA CORPORATION is strictly prohibited. +*/ + +#include "omm.h" + +#pragma once + +namespace omm +{ + enum class HandleType : uint8_t + { + Reserved, // keep zero reserved + GpuBaker, + Pipeline, + CpuBaker, + Texture, + BakeResult, + SerializeResult, + DeserializeResult + }; + + template + inline bool CheckHandle(THandlePtr handle) { + return static_cast((uintptr_t)handle & 0x7ull) == T::kHandleType; + } + + template + inline HandleType GetHandleType(THandlePtr handle) { + return static_cast((uintptr_t)handle & 0x7ull); + } + + template + inline T* GetHandleImpl(THandlePtr handle) { + return reinterpret_cast((uintptr_t)handle & 0xFFFFFFFFFFFFFFF8ull); + } + + template + inline T* GetCheckedHandleImpl(THandlePtr handle) { + T* ptr = reinterpret_cast((uintptr_t)handle & 0xFFFFFFFFFFFFFFF8ull); + HandleType type = (HandleType)((uintptr_t)handle & 0x7ull); + return T::kHandleType == type ? ptr : nullptr; + } + + template + inline THandlePtr CreateHandle(T* impl) { + return (THandlePtr)((uintptr_t)(impl) | (uintptr_t)T::kHandleType); + } + +} // namespace \ No newline at end of file diff --git a/omm-sdk/src/serialize_impl.cpp b/omm-sdk/src/serialize_impl.cpp new file mode 100644 index 0000000..04231a7 --- /dev/null +++ b/omm-sdk/src/serialize_impl.cpp @@ -0,0 +1,494 @@ +/* +Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. + +NVIDIA CORPORATION and its licensors retain all intellectual property +and proprietary rights in and to this software, related documentation +and any modifications thereto. Any use, reproduction, disclosure or +distribution of this software and related documentation without an express +license agreement from NVIDIA CORPORATION is strictly prohibited. +*/ + +#include "omm_handle.h" +#include "serialize_impl.h" +#include + +namespace omm +{ +namespace Cpu +{ + class MemoryStreamBuf : public std::streambuf { + public: + MemoryStreamBuf(uint8_t* data, size_t size) { + setg((char*)data, (char*)data, (char*)data + size); + setp((char*)data, (char*)data + size); + } + }; + + class PassthroughStreamBuf : public std::streambuf { + public: + PassthroughStreamBuf() { } + + std::streamsize GetWrittenSize() const + { + return written_size; + } + + std::streamsize xsputn(const char* s, std::streamsize n) override { + written_size += n; + return n; + } + private: + std::streamsize written_size = 0; + }; + + template + void WriteArray(std::ostream& os, const TElem* data, uint32_t elementCount) + { + os.write(reinterpret_cast(&elementCount), sizeof(elementCount)); + if (elementCount != 0) + os.write(reinterpret_cast(data), sizeof(TElem) * elementCount); + }; + + template + void ReadArray(std::istream& os, StdAllocator& stdAllocator, const TElem*& outData, uint32_t& outElementCount) + { + os.read(reinterpret_cast(&outElementCount), sizeof(outElementCount)); + if (outElementCount != 0) + { + size_t dataSize = sizeof(TElem) * outElementCount; + uint8_t* data = stdAllocator.allocate(dataSize, 16); + os.read(reinterpret_cast(data), dataSize); + outData = (TElem*)data; + } + else + { + outData = nullptr; + } + }; + + SerializeResultImpl::SerializeResultImpl(const StdAllocator& stdAllocator, const Logger& log) + : m_stdAllocator(stdAllocator) + , m_log(log) + , m_desc(ommCpuBlobDescDefault()) + { + } + + SerializeResultImpl::~SerializeResultImpl() + { + if (m_desc.data != nullptr) + { + m_stdAllocator.deallocate((uint8_t*)m_desc.data, 0); + } + } + + uint32_t SerializeResultImpl::_GetMaxIndex(const ommCpuBakeInputDesc& inputDesc) + { + uint32_t maxIndex = 0; + const int32_t triangleCount = inputDesc.indexCount / 3u; + + for (int32_t i = 0; i < triangleCount; ++i) + { + uint32_t triangleIndices[3]; + GetUInt32Indices(inputDesc.indexFormat, inputDesc.indexBuffer, 3ull * i, triangleIndices); + + maxIndex = std::max(maxIndex, triangleIndices[0]); + maxIndex = std::max(maxIndex, triangleIndices[1]); + maxIndex = std::max(maxIndex, triangleIndices[2]); + } + + return maxIndex; + } + + template + ommResult SerializeResultImpl::_Serialize(const ommCpuBakeInputDesc& inputDesc, TMemoryStreamBuf& buffer) + { + std::ostream os(&buffer); + + static_assert(sizeof(ommCpuBakeInputDesc) == 128); + + os.write(reinterpret_cast(&inputDesc.bakeFlags), sizeof(inputDesc.bakeFlags)); + + const TextureImpl* texture = GetHandleImpl(inputDesc.texture); + texture->Serialize(buffer); + + os.write(reinterpret_cast(&inputDesc.runtimeSamplerDesc.addressingMode), sizeof(inputDesc.runtimeSamplerDesc.addressingMode)); + os.write(reinterpret_cast(&inputDesc.runtimeSamplerDesc.filter), sizeof(inputDesc.runtimeSamplerDesc.filter)); + os.write(reinterpret_cast(&inputDesc.runtimeSamplerDesc.borderAlpha), sizeof(inputDesc.runtimeSamplerDesc.borderAlpha)); + os.write(reinterpret_cast(&inputDesc.alphaMode), sizeof(inputDesc.alphaMode)); + + os.write(reinterpret_cast(&inputDesc.texCoordFormat), sizeof(inputDesc.texCoordFormat)); + const size_t texCoordsSize = GetTexCoordFormatSize(inputDesc.texCoordFormat) * (_GetMaxIndex(inputDesc) + 1); + os.write(reinterpret_cast(&texCoordsSize), sizeof(texCoordsSize)); + if (texCoordsSize != 0) + { + os.write(reinterpret_cast(inputDesc.texCoords), texCoordsSize); + } + os.write(reinterpret_cast(&inputDesc.texCoordStrideInBytes), sizeof(inputDesc.texCoordStrideInBytes)); + + os.write(reinterpret_cast(&inputDesc.indexFormat), sizeof(inputDesc.indexFormat)); + os.write(reinterpret_cast(&inputDesc.indexCount), sizeof(inputDesc.indexCount)); + + static_assert(ommIndexFormat_MAX_NUM == 2); + size_t indexBufferSize = inputDesc.indexCount * (inputDesc.indexFormat == ommIndexFormat_UINT_16 ? 2 : 4); + os.write(reinterpret_cast(inputDesc.indexBuffer), indexBufferSize); + + os.write(reinterpret_cast(&inputDesc.dynamicSubdivisionScale), sizeof(inputDesc.dynamicSubdivisionScale)); + os.write(reinterpret_cast(&inputDesc.rejectionThreshold), sizeof(inputDesc.rejectionThreshold)); + os.write(reinterpret_cast(&inputDesc.alphaCutoff), sizeof(inputDesc.alphaCutoff)); + os.write(reinterpret_cast(&inputDesc.alphaCutoffLessEqual), sizeof(inputDesc.alphaCutoffLessEqual)); + os.write(reinterpret_cast(&inputDesc.alphaCutoffGreater), sizeof(inputDesc.alphaCutoffGreater)); + os.write(reinterpret_cast(&inputDesc.format), sizeof(inputDesc.format)); + + size_t numFormats = inputDesc.formats == nullptr ? 0 : inputDesc.indexCount; + os.write(reinterpret_cast(&numFormats), sizeof(numFormats)); + + if (numFormats != 0) + { + os.write(reinterpret_cast(inputDesc.formats), numFormats * sizeof(ommFormat)); + } + + os.write(reinterpret_cast(&inputDesc.unknownStatePromotion), sizeof(inputDesc.unknownStatePromotion)); + os.write(reinterpret_cast(&inputDesc.maxSubdivisionLevel), sizeof(inputDesc.maxSubdivisionLevel)); + + size_t numSubdivLvls = inputDesc.subdivisionLevels == nullptr ? 0 : inputDesc.indexCount; + os.write(reinterpret_cast(&numSubdivLvls), sizeof(numSubdivLvls)); + if (numSubdivLvls != 0) + { + os.write(reinterpret_cast(inputDesc.subdivisionLevels), numSubdivLvls * sizeof(uint8_t)); + } + + os.write(reinterpret_cast(&inputDesc.maxWorkloadSize), sizeof(inputDesc.maxWorkloadSize)); + + return ommResult_SUCCESS; + } + + template + ommResult SerializeResultImpl::_Serialize(const ommCpuBakeResultDesc& resultDesc, TMemoryStreamBuf& buffer) + { + std::ostream os(&buffer); + + WriteArray(os, (const uint8_t*)resultDesc.arrayData, resultDesc.arrayDataSize); + WriteArray(os, resultDesc.descArray, resultDesc.descArrayCount); + WriteArray(os, resultDesc.descArrayHistogram, resultDesc.descArrayHistogramCount); + + os.write(reinterpret_cast(&resultDesc.indexFormat), sizeof(resultDesc.indexFormat)); + if (resultDesc.indexFormat == ommIndexFormat_UINT_16) + { + WriteArray(os, (const uint16_t*)resultDesc.indexBuffer, resultDesc.indexCount); + } + else + { + OMM_ASSERT(resultDesc.indexFormat == ommIndexFormat_UINT_32); + WriteArray(os, (const uint32_t*)resultDesc.indexBuffer, resultDesc.indexCount); + } + + WriteArray(os, resultDesc.indexHistogram, resultDesc.indexHistogramCount); + + return ommResult_SUCCESS; + } + + template + ommResult SerializeResultImpl::_Serialize(const ommCpuDeserializedDesc& inputDesc, TMemoryStreamBuf& buffer) + { + std::ostream os(&buffer); + + // BEGIN HEADER + // Reserve space for the digest + XXH64_hash_t digest = { 0 }; + os.write(reinterpret_cast(&digest), sizeof(digest)); + int major = OMM_VERSION_MAJOR; + int minor = OMM_VERSION_MINOR; + int patch = OMM_VERSION_BUILD; + int inputDescVersion = SerializeResultImpl::VERSION; + os.write(reinterpret_cast(&major), sizeof(major)); + os.write(reinterpret_cast(&minor), sizeof(minor)); + os.write(reinterpret_cast(&patch), sizeof(patch)); + os.write(reinterpret_cast(&inputDescVersion), sizeof(inputDescVersion)); + // END HEADER + + os.write(reinterpret_cast(&inputDesc.flags), sizeof(inputDesc.flags)); + + os.write(reinterpret_cast(&inputDesc.numInputDescs), sizeof(inputDesc.numInputDescs)); + for (int i = 0; i < inputDesc.numInputDescs; ++i) + { + _Serialize(inputDesc.inputDescs[i], buffer); + } + + os.write(reinterpret_cast(&inputDesc.numResultDescs), sizeof(inputDesc.numResultDescs)); + for (int i = 0; i < inputDesc.numResultDescs; ++i) + { + _Serialize(inputDesc.resultDescs[i], buffer); + } + + return ommResult_SUCCESS; + } + + ommResult SerializeResultImpl::Serialize(const ommCpuDeserializedDesc& desc) + { + PassthroughStreamBuf passthrough; + RETURN_STATUS_IF_FAILED(_Serialize(desc, passthrough)); + + size_t size = passthrough.GetWrittenSize(); + + m_desc.data = m_stdAllocator.allocate(size, 16); + m_desc.size = size; + + MemoryStreamBuf buf((uint8_t*)m_desc.data, m_desc.size); + RETURN_STATUS_IF_FAILED(_Serialize(desc, buf)); + + // Compute the digest + XXH64_hash_t hash = XXH64((uint8_t*)m_desc.data + sizeof(XXH64_hash_t), m_desc.size - sizeof(XXH64_hash_t), 42/*seed*/); + *(XXH64_hash_t*)m_desc.data = hash; + + return ommResult_SUCCESS; + } + + DeserializedResultImpl::DeserializedResultImpl(const StdAllocator& stdAllocator, const Logger& log) + : m_stdAllocator(stdAllocator) + , m_log(log) + , m_inputDesc(ommCpuDeserializedDescDefault()) + { + } + + DeserializedResultImpl::~DeserializedResultImpl() + { + for (int i = 0; i < m_inputDesc.numInputDescs; ++i) + { + auto& inputDesc = m_inputDesc.inputDescs[i]; + OMM_ASSERT(inputDesc.texture != 0); + if (inputDesc.texture) + { + const StdAllocator& memoryAllocator = GetStdAllocator(); + TextureImpl* texture = GetHandleImpl(inputDesc.texture); + Deallocate(memoryAllocator, texture); + } + + if (inputDesc.texCoords) + { + m_stdAllocator.deallocate((uint8_t*)inputDesc.texCoords, 0); + } + + if (inputDesc.indexBuffer) + { + m_stdAllocator.deallocate((uint8_t*)inputDesc.indexBuffer, 0); + } + + if (inputDesc.formats) + { + m_stdAllocator.deallocate((uint8_t*)inputDesc.formats, 0); + } + + if (inputDesc.subdivisionLevels) + { + m_stdAllocator.deallocate((uint8_t*)inputDesc.subdivisionLevels, 0); + } + } + + for (int i = 0; i < m_inputDesc.numResultDescs; ++i) + { + auto& resultDesc = m_inputDesc.resultDescs[i]; + + if (resultDesc.arrayData) + { + m_stdAllocator.deallocate((uint8_t*)resultDesc.arrayData, 0); + } + + if (resultDesc.descArray) + { + m_stdAllocator.deallocate((uint8_t*)resultDesc.descArray, 0); + } + + if (resultDesc.descArrayHistogram) + { + m_stdAllocator.deallocate((uint8_t*)resultDesc.descArrayHistogram, 0); + } + + if (resultDesc.indexBuffer) + { + m_stdAllocator.deallocate((uint8_t*)resultDesc.indexBuffer, 0); + } + + if (resultDesc.indexHistogram) + { + m_stdAllocator.deallocate((uint8_t*)resultDesc.indexHistogram, 0); + } + } + } + + template + ommResult DeserializedResultImpl::_Deserialize(ommCpuBakeInputDesc& inputDesc, TMemoryStreamBuf& buffer) + { + std::istream os(&buffer); + + static_assert(sizeof(ommCpuBakeInputDesc) == 128); + + os.read(reinterpret_cast(&inputDesc.bakeFlags), sizeof(inputDesc.bakeFlags)); + + TextureImpl* texture = Allocate(m_stdAllocator, m_stdAllocator, m_log); + texture->Deserialize(buffer); + inputDesc.texture = CreateHandle(texture); + + os.read(reinterpret_cast(&inputDesc.runtimeSamplerDesc.addressingMode), sizeof(inputDesc.runtimeSamplerDesc.addressingMode)); + os.read(reinterpret_cast(&inputDesc.runtimeSamplerDesc.filter), sizeof(inputDesc.runtimeSamplerDesc.filter)); + os.read(reinterpret_cast(&inputDesc.runtimeSamplerDesc.borderAlpha), sizeof(inputDesc.runtimeSamplerDesc.borderAlpha)); + os.read(reinterpret_cast(&inputDesc.alphaMode), sizeof(inputDesc.alphaMode)); + + os.read(reinterpret_cast(&inputDesc.texCoordFormat), sizeof(inputDesc.texCoordFormat)); + + size_t texCoordsSize = 0; + os.read(reinterpret_cast(&texCoordsSize), sizeof(texCoordsSize)); + if (texCoordsSize != 0) + { + uint8_t* texCoords = m_stdAllocator.allocate(texCoordsSize, 16); + os.read(reinterpret_cast(texCoords), texCoordsSize); + inputDesc.texCoords = texCoords; + } + os.read(reinterpret_cast(&inputDesc.texCoordStrideInBytes), sizeof(inputDesc.texCoordStrideInBytes)); + + os.read(reinterpret_cast(&inputDesc.indexFormat), sizeof(inputDesc.indexFormat)); + os.read(reinterpret_cast(&inputDesc.indexCount), sizeof(inputDesc.indexCount)); + + static_assert(ommIndexFormat_MAX_NUM == 2); + const size_t indexBufferSize = inputDesc.indexCount * (inputDesc.indexFormat == ommIndexFormat_UINT_16 ? 2 : 4); + uint8_t* indexBuffer = m_stdAllocator.allocate(indexBufferSize, 16); + os.read(reinterpret_cast(indexBuffer), indexBufferSize); + inputDesc.indexBuffer = indexBuffer; + + os.read(reinterpret_cast(&inputDesc.dynamicSubdivisionScale), sizeof(inputDesc.dynamicSubdivisionScale)); + os.read(reinterpret_cast(&inputDesc.rejectionThreshold), sizeof(inputDesc.rejectionThreshold)); + os.read(reinterpret_cast(&inputDesc.alphaCutoff), sizeof(inputDesc.alphaCutoff)); + os.read(reinterpret_cast(&inputDesc.alphaCutoffLessEqual), sizeof(inputDesc.alphaCutoffLessEqual)); + os.read(reinterpret_cast(&inputDesc.alphaCutoffGreater), sizeof(inputDesc.alphaCutoffGreater)); + os.read(reinterpret_cast(&inputDesc.format), sizeof(inputDesc.format)); + + size_t numFormats = 0; + os.read(reinterpret_cast(&numFormats), sizeof(numFormats)); + if (numFormats != 0) + { + const size_t formatsSize = numFormats * sizeof(ommFormat); + uint8_t* formats = m_stdAllocator.allocate(formatsSize, 16); + os.read(reinterpret_cast(formats), formatsSize); + inputDesc.formats = (ommFormat*)formats; + } + + os.read(reinterpret_cast(&inputDesc.unknownStatePromotion), sizeof(inputDesc.unknownStatePromotion)); + os.read(reinterpret_cast(&inputDesc.maxSubdivisionLevel), sizeof(inputDesc.maxSubdivisionLevel)); + + size_t numSubdivLvls = 0; + os.read(reinterpret_cast(&numSubdivLvls), sizeof(numSubdivLvls)); + if (numSubdivLvls != 0) + { + const size_t subdivLvlSize = numSubdivLvls * sizeof(uint8_t); + uint8_t* subdivisionLevels = m_stdAllocator.allocate(subdivLvlSize, 16); + os.read(reinterpret_cast(subdivisionLevels), subdivLvlSize); + inputDesc.subdivisionLevels = subdivisionLevels; + } + + os.read(reinterpret_cast(&inputDesc.maxWorkloadSize), sizeof(inputDesc.maxWorkloadSize)); + + return ommResult_SUCCESS; + } + + template + ommResult DeserializedResultImpl::_Deserialize(ommCpuBakeResultDesc& resultDesc, TMemoryStreamBuf& buffer) + { + std::istream os(&buffer); + + StdAllocator& mem = m_stdAllocator; + + ReadArray(os, mem, reinterpret_cast(resultDesc.arrayData), resultDesc.arrayDataSize); + ReadArray(os, mem, resultDesc.descArray, resultDesc.descArrayCount); + ReadArray(os, mem, resultDesc.descArrayHistogram, resultDesc.descArrayHistogramCount); + + os.read(reinterpret_cast(&resultDesc.indexFormat), sizeof(resultDesc.indexFormat)); + + if (resultDesc.indexFormat == ommIndexFormat_UINT_16) + { + ReadArray(os, mem, reinterpret_cast(resultDesc.indexBuffer), resultDesc.indexCount); + } + else + { + OMM_ASSERT(resultDesc.indexFormat == ommIndexFormat_UINT_32); + ReadArray(os, mem, reinterpret_cast(resultDesc.indexBuffer), resultDesc.indexCount); + } + + ReadArray(os, mem, resultDesc.indexHistogram, resultDesc.indexHistogramCount); + + return ommResult_SUCCESS; + } + + template + ommResult DeserializedResultImpl::_Deserialize(XXH64_hash_t hash, ommCpuDeserializedDesc& desc, TMemoryStreamBuf& buffer) + { + std::istream os(&buffer); + + // BEGIN HEADER + XXH64_hash_t storedHash; + os.read(reinterpret_cast(&storedHash), sizeof(storedHash)); + + if (hash != storedHash) + { + return m_log.InvalidArgf("The serialized blob appears corrupted, computed digest != header value %ull, %ull", hash, storedHash); + } + + int major = 0; + int minor = 0; + int patch = 0; + int inputDescVersion = 0; + os.read(reinterpret_cast(&major), sizeof(major)); + os.read(reinterpret_cast(&minor), sizeof(minor)); + os.read(reinterpret_cast(&patch), sizeof(patch)); + os.read(reinterpret_cast(&inputDescVersion), sizeof(inputDescVersion)); + // END HEADER + + if (inputDescVersion != SerializeResultImpl::VERSION) + { + return m_log.InvalidArgf("The serialized blob appears to be generated from an incompatible version of the SDK (%d.%d.%d:%d)", major, minor, patch, inputDescVersion); + } + + os.read(reinterpret_cast(&desc.flags), sizeof(desc.flags)); + + os.read(reinterpret_cast(&desc.numInputDescs), sizeof(desc.numInputDescs)); + if (desc.numInputDescs != 0) + { + ommCpuBakeInputDesc* inputDescs = AllocateArray(m_stdAllocator, desc.numInputDescs); + for (int i = 0; i < desc.numInputDescs; ++i) + { + inputDescs[i] = ommCpuBakeInputDescDefault(); + _Deserialize(inputDescs[i], buffer); + } + desc.inputDescs = inputDescs; + } + + os.read(reinterpret_cast(&desc.numResultDescs), sizeof(desc.numResultDescs)); + if (desc.numResultDescs != 0) + { + ommCpuBakeResultDesc* resultDescs = AllocateArray(m_stdAllocator, desc.numResultDescs); + for (int i = 0; i < desc.numResultDescs; ++i) + { + // resultDescs[i] = ommCpuBakeResultDescDefault(); + _Deserialize(resultDescs[i], buffer); + } + desc.resultDescs = resultDescs; + } + + return ommResult_SUCCESS; + } + + ommResult DeserializedResultImpl::Deserialize(const ommCpuBlobDesc& desc) + { + if (desc.data == nullptr) + return m_log.InvalidArg("data must be non-null"); + if (desc.size == 0) + return m_log.InvalidArg("size must be non-zero"); + + MemoryStreamBuf buf((uint8_t*)desc.data, desc.size); + + // Compute the digest + XXH64_hash_t hash = XXH64((const uint8_t*)desc.data + sizeof(XXH64_hash_t), desc.size - sizeof(XXH64_hash_t), 42/*seed*/); + + return _Deserialize(hash, m_inputDesc, buf); + } + +} // namespace Cpu +} // namespace omm \ No newline at end of file diff --git a/omm-sdk/src/serialize_impl.h b/omm-sdk/src/serialize_impl.h new file mode 100644 index 0000000..13b4fba --- /dev/null +++ b/omm-sdk/src/serialize_impl.h @@ -0,0 +1,106 @@ +/* +Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. + +NVIDIA CORPORATION and its licensors retain all intellectual property +and proprietary rights in and to this software, related documentation +and any modifications thereto. Any use, reproduction, disclosure or +distribution of this software and related documentation without an express +license agreement from NVIDIA CORPORATION is strictly prohibited. +*/ + +#pragma once + +#include "omm.h" +#include "defines.h" +#include "std_containers.h" +#include "texture_impl.h" +#include "log.h" + +#include +#include + +#include +#include + +#include "std_allocator.h" + +typedef uint64_t XXH64_hash_t; + +namespace omm +{ +namespace Cpu +{ + class SerializeResultImpl + { + public: + static inline constexpr HandleType kHandleType = HandleType::SerializeResult; + + enum { + VERSION = 1 + }; + + SerializeResultImpl(const StdAllocator& stdAllocator, const Logger& log); + ~SerializeResultImpl(); + + inline const StdAllocator& GetStdAllocator() const + { + return m_stdAllocator; + } + + const ommCpuBlobDesc* GetDesc() const + { + return &m_desc; + } + + ommResult Serialize(const ommCpuDeserializedDesc& desc); + + private: + static uint32_t _GetMaxIndex(const ommCpuBakeInputDesc& inputDesc); + + template + ommResult _Serialize(const ommCpuBakeInputDesc& inputDesc, TMemoryStreamBuf& buffer); + template + ommResult _Serialize(const ommCpuBakeResultDesc& resultDesc, TMemoryStreamBuf& buffer); + template + ommResult _Serialize(const ommCpuDeserializedDesc& desc, TMemoryStreamBuf& buffer); + + StdAllocator m_stdAllocator; + const Logger& m_log; + ommCpuBlobDesc m_desc; + }; + + class DeserializedResultImpl + { + public: + static inline constexpr HandleType kHandleType = HandleType::DeserializeResult; + + DeserializedResultImpl(const StdAllocator& stdAllocator, const Logger& log); + ~DeserializedResultImpl(); + + inline const StdAllocator& GetStdAllocator() const + { + return m_stdAllocator; + } + + const ommCpuDeserializedDesc* GetDesc() const + { + return &m_inputDesc; + } + + ommResult Deserialize(const ommCpuBlobDesc& desc); + + private: + + template + ommResult _Deserialize(ommCpuBakeInputDesc& inputDesc, TMemoryStreamBuf& buffer); + template + ommResult _Deserialize(ommCpuBakeResultDesc& resultDesc, TMemoryStreamBuf& buffer); + template + ommResult _Deserialize(XXH64_hash_t hash, ommCpuDeserializedDesc& desc, TMemoryStreamBuf& buffer); + + StdAllocator m_stdAllocator; + const Logger& m_log; + ommCpuDeserializedDesc m_inputDesc; + }; +} // namespace Cpu +} // namespace omm diff --git a/omm-sdk/src/std_allocator.h b/omm-sdk/src/std_allocator.h index 7c64400..2ba8194 100644 --- a/omm-sdk/src/std_allocator.h +++ b/omm-sdk/src/std_allocator.h @@ -216,7 +216,7 @@ constexpr void Construct(T* objects, size_t number, Args&&... args) } template -inline T* Allocate(StdAllocator& allocator, Args&&... args) +inline T* Allocate(const StdAllocator& allocator, Args&&... args) { const auto& lowLevelAllocator = allocator.GetInterface(); T* object = (T*)lowLevelAllocator.Allocate(lowLevelAllocator.UserArg, sizeof(T), alignof(T)); @@ -238,7 +238,7 @@ inline T* AllocateArray(StdAllocator& allocator, size_t arraySize, Args } template -inline void Deallocate(StdAllocator& allocator, T* object) +inline void Deallocate(const StdAllocator& allocator, T* object) { if (object == nullptr) return; diff --git a/omm-sdk/src/std_containers.h b/omm-sdk/src/std_containers.h index 5bd8afb..97ec1b7 100644 --- a/omm-sdk/src/std_containers.h +++ b/omm-sdk/src/std_containers.h @@ -15,6 +15,9 @@ license agreement from NVIDIA CORPORATION is strictly prohibited. #include #include #include +#include +#include +#include #include "omm.h" diff --git a/omm-sdk/src/texture_impl.cpp b/omm-sdk/src/texture_impl.cpp index f1134ca..f9cd853 100644 --- a/omm-sdk/src/texture_impl.cpp +++ b/omm-sdk/src/texture_impl.cpp @@ -29,7 +29,9 @@ namespace omm m_tilingMode(TilingMode::MAX_NUM), m_alphaCutoff(-1.f), m_data(nullptr), - m_dataSAT(nullptr) + m_dataSize(0), + m_dataSAT(nullptr), + m_dataSATSize(0) { } @@ -86,15 +88,15 @@ namespace omm const bool enableSAT = std::numeric_limits::max() > m_mips[0].numElements && m_alphaCutoff >= 0; - size_t totalSize = 0; - size_t totalSizeSAT = 0; + m_dataSize = 0; + m_dataSATSize = 0; for (uint32_t mipIt = 0; mipIt < desc.mipCount; ++mipIt) { m_mips[mipIt].size = { desc.mips[mipIt].width, desc.mips[mipIt].height }; m_mips[mipIt].sizeMinusOne = m_mips[mipIt].size - 1; m_mips[mipIt].rcpSize = 1.f / (float2)m_mips[mipIt].size; - m_mips[mipIt].dataOffset = totalSize; - m_mips[mipIt].dataOffsetSAT = totalSizeSAT; + m_mips[mipIt].dataOffset = m_dataSize; + m_mips[mipIt].dataOffsetSAT = m_dataSATSize; if (m_tilingMode == TilingMode::Linear) { @@ -111,18 +113,18 @@ namespace omm return ommResult_FAILURE; } - totalSize += sizePerPixel * m_mips[mipIt].numElements; - totalSize = math::Align(totalSize, kAlignment); + m_dataSize += sizePerPixel * m_mips[mipIt].numElements; + m_dataSize = math::Align(m_dataSize, kAlignment); if (enableSAT) { - totalSizeSAT += sizeof(uint32_t) * m_mips[mipIt].numElements;; - totalSizeSAT = math::Align(totalSizeSAT, kAlignment); + m_dataSATSize += sizeof(uint32_t) * m_mips[mipIt].numElements;; + m_dataSATSize = math::Align(m_dataSATSize, kAlignment); } } - m_data = m_stdAllocator.allocate(totalSize, kAlignment); - m_dataSAT = enableSAT ? m_stdAllocator.allocate(totalSizeSAT, kAlignment) : nullptr; + m_data = m_stdAllocator.allocate(m_dataSize, kAlignment); + m_dataSAT = enableSAT ? m_stdAllocator.allocate(m_dataSATSize, kAlignment) : nullptr; for (uint32_t mipIt = 0; mipIt < desc.mipCount; ++mipIt) { diff --git a/omm-sdk/src/texture_impl.h b/omm-sdk/src/texture_impl.h index e42a04b..604518d 100644 --- a/omm-sdk/src/texture_impl.h +++ b/omm-sdk/src/texture_impl.h @@ -11,6 +11,7 @@ license agreement from NVIDIA CORPORATION is strictly prohibited. #pragma once #include "omm.h" +#include "omm_handle.h" #include "std_containers.h" #include "log.h" @@ -31,6 +32,8 @@ namespace omm class TextureImpl { public: + static inline constexpr HandleType kHandleType = HandleType::Texture; + TextureImpl(const StdAllocator& stdAllocator, const Logger& log); ~TextureImpl(); @@ -115,6 +118,12 @@ namespace omm #endif } + template + void Serialize(TMemoryStreamBuf& buffer) const; + + template + void Deserialize(TMemoryStreamBuf& buffer); + private: ommResult Validate(const ommCpuTextureDesc& desc) const; void Deallocate(); @@ -145,7 +154,9 @@ namespace omm ommCpuTextureFormat m_textureFormat; float m_alphaCutoff; uint8_t* m_data; + size_t m_dataSize; uint8_t* m_dataSAT; + size_t m_dataSATSize; }; template @@ -175,4 +186,83 @@ namespace omm template<> uint64_t TextureImpl::From2Dto1D(const int2& idx, const int2& size); template<> uint64_t TextureImpl::From2Dto1D(const int2& idx, const int2& size); + + template + void TextureImpl::Serialize(TMemoryStreamBuf& buffer) const + { + std::ostream os(&buffer); + + int numMips = (int)m_mips.size(); + os.write(reinterpret_cast(&numMips), sizeof(numMips)); + + if (numMips != 0) + { + for (const auto& mip : m_mips) + { + os.write(reinterpret_cast(&mip.size.x), sizeof(mip.size.x)); + os.write(reinterpret_cast(&mip.size.y), sizeof(mip.size.y)); + os.write(reinterpret_cast(&mip.rcpSize.x), sizeof(mip.rcpSize.x)); + os.write(reinterpret_cast(&mip.rcpSize.y), sizeof(mip.rcpSize.y)); + os.write(reinterpret_cast(&mip.dataOffset), sizeof(mip.dataOffset)); + os.write(reinterpret_cast(&mip.numElements), sizeof(mip.numElements)); + os.write(reinterpret_cast(&mip.dataOffsetSAT), sizeof(mip.dataOffsetSAT)); + } + } + + os.write(reinterpret_cast(&m_tilingMode), sizeof(m_tilingMode)); + os.write(reinterpret_cast(&m_textureFormat), sizeof(m_textureFormat)); + + os.write(reinterpret_cast(&m_dataSize), sizeof(m_dataSize)); + os.write(reinterpret_cast(m_data), m_dataSize); + + os.write(reinterpret_cast(&m_dataSATSize), sizeof(m_dataSATSize)); + if (m_dataSATSize != 0) + { + os.write(reinterpret_cast(m_dataSAT), m_dataSATSize); + } + } + + template + void TextureImpl::Deserialize(TMemoryStreamBuf& buffer) + { + OMM_ASSERT(m_data == nullptr); + OMM_ASSERT(m_dataSize == 0); + OMM_ASSERT(m_dataSAT == nullptr); + OMM_ASSERT(m_dataSATSize == 0); + OMM_ASSERT(m_mips.size() == 0); + + std::istream os(&buffer); + + int numMips = 0; + os.read(reinterpret_cast(&numMips), sizeof(numMips)); + + if (numMips != 0) + { + m_mips.resize(numMips); + for (auto& mip : m_mips) + { + os.read(reinterpret_cast(&mip.size.x), sizeof(mip.size.x)); + os.read(reinterpret_cast(&mip.size.y), sizeof(mip.size.y)); + os.read(reinterpret_cast(&mip.rcpSize.x), sizeof(mip.rcpSize.x)); + os.read(reinterpret_cast(&mip.rcpSize.y), sizeof(mip.rcpSize.y)); + os.read(reinterpret_cast(&mip.dataOffset), sizeof(mip.dataOffset)); + os.read(reinterpret_cast(&mip.numElements), sizeof(mip.numElements)); + os.read(reinterpret_cast(&mip.dataOffsetSAT), sizeof(mip.dataOffsetSAT)); + } + } + + os.read(reinterpret_cast(&m_tilingMode), sizeof(m_tilingMode)); + os.read(reinterpret_cast(&m_textureFormat), sizeof(m_textureFormat)); + + os.read(reinterpret_cast(&m_dataSize), sizeof(m_dataSize)); + m_data = m_stdAllocator.allocate(m_dataSize, kAlignment); + os.read(reinterpret_cast(m_data), m_dataSize); + + os.read(reinterpret_cast(&m_dataSATSize), sizeof(m_dataSATSize)); + if (m_dataSATSize != 0) + { + m_dataSAT = m_stdAllocator.allocate(m_dataSATSize, kAlignment); + os.read(reinterpret_cast(m_dataSAT), m_dataSATSize); + } + } } diff --git a/omm-sdk/src/version.h b/omm-sdk/src/version.h index be1199e..ef0a7b7 100644 --- a/omm-sdk/src/version.h +++ b/omm-sdk/src/version.h @@ -12,7 +12,7 @@ license agreement from NVIDIA CORPORATION is strictly prohibited. #define STR(x) STR_HELPER(x) #define VERSION_MAJOR 1 -#define VERSION_MINOR 3 +#define VERSION_MINOR 4 #define VERSION_BUILD 0 #define VERSION_REVISION 0 diff --git a/tests/test_basic.cpp b/tests/test_basic.cpp index 07698dc..9816d2b 100644 --- a/tests/test_basic.cpp +++ b/tests/test_basic.cpp @@ -27,26 +27,26 @@ namespace { TEST(Baker, DestroyNull) { - omm::Baker baker = 0; + omm::Baker baker = nullptr; EXPECT_EQ(omm::DestroyBaker(baker), omm::Result::INVALID_ARGUMENT); } TEST(Baker, CreateDestroy) { - omm::Baker baker = 0; + omm::Baker baker = nullptr; EXPECT_EQ(omm::CreateBaker({ .type = omm::BakerType::CPU }, &baker), omm::Result::SUCCESS); - EXPECT_NE(baker, 0); + EXPECT_NE(baker, nullptr); EXPECT_EQ(omm::DestroyBaker(baker), omm::Result::SUCCESS); } TEST(Baker, CreateInvalid) { - omm::Baker baker = 0; + omm::Baker baker = nullptr; EXPECT_EQ(omm::CreateBaker({.type = omm::BakerType::MAX_NUM}, &baker), omm::Result::INVALID_ARGUMENT); } TEST(Baker, CreateDestroyGPU) { omm::Baker baker = 0; EXPECT_EQ(omm::CreateBaker({ .type = omm::BakerType::GPU }, &baker), omm::Result::SUCCESS); - EXPECT_NE(baker, 0); + EXPECT_NE(baker, nullptr); EXPECT_EQ(omm::DestroyBaker(baker), omm::Result::SUCCESS); } @@ -224,7 +224,7 @@ namespace { vmtest::TextureFP32 tex(64, 100, 1, true /*enableZorder*/, -1.f /*alphaCutoff*/, [](int i, int j, int w, int h, int mip)->float {return 0.f; }); omm::Cpu::Texture outTexture = 0; EXPECT_EQ(omm::Cpu::CreateTexture(_baker, tex.GetDesc(), &outTexture), omm::Result::SUCCESS); - EXPECT_NE(outTexture, 0); + EXPECT_NE(outTexture, nullptr); EXPECT_EQ(omm::Cpu::DestroyTexture(_baker, outTexture), omm::Result::SUCCESS); } @@ -234,7 +234,7 @@ namespace { omm::Cpu::Texture outTexture = 0; EXPECT_EQ(omm::Cpu::CreateTexture(_baker, tex.GetDesc(), &outTexture), omm::Result::SUCCESS); - EXPECT_NE(outTexture, 0); + EXPECT_NE(outTexture, nullptr); EXPECT_EQ(omm::Cpu::DestroyTexture(_baker, outTexture), omm::Result::SUCCESS); } @@ -244,7 +244,7 @@ namespace { omm::Cpu::Texture outTexture = 0; EXPECT_EQ(omm::Cpu::CreateTexture(_baker, tex.GetDesc(), &outTexture), omm::Result::SUCCESS); - EXPECT_NE(outTexture, 0); + EXPECT_NE(outTexture, nullptr); EXPECT_EQ(omm::Cpu::DestroyTexture(_baker, outTexture), omm::Result::SUCCESS); } diff --git a/tests/test_omm_bake_cpu.cpp b/tests/test_omm_bake_cpu.cpp index d833d49..48f6884 100644 --- a/tests/test_omm_bake_cpu.cpp +++ b/tests/test_omm_bake_cpu.cpp @@ -21,6 +21,12 @@ license agreement from NVIDIA CORPORATION is strictly prohibited. #include #include +#include +#include +#include +#include +#include + namespace { enum TestSuiteConfig @@ -30,6 +36,7 @@ namespace { Force32BitIndices, TextureAsUNORM8, AlphaCutoff, + Serialize, }; struct Options @@ -44,6 +51,9 @@ namespace { bool monochromeUnknowns = false; omm::OpacityState alphaCutoffLE = omm::OpacityState::Transparent; omm::OpacityState alphaCutoffGT = omm::OpacityState::Opaque; + uint64_t maxWorkloadSize = 0xFFFFFFFFFFFFFFFF; + omm::Result bakeResult = omm::Result::SUCCESS; + bool forceCorruptedBlob = false; }; class OMMBakeTestCPU : public ::testing::TestWithParam { @@ -64,7 +74,8 @@ namespace { bool Force32BitIndices() const { return (GetParam() & TestSuiteConfig::Force32BitIndices) == TestSuiteConfig::Force32BitIndices; } bool TextureAsUNORM8() const { return (GetParam() & TestSuiteConfig::TextureAsUNORM8) == TestSuiteConfig::TextureAsUNORM8; } bool EnableAlphaCutoff() const { return (GetParam() & TestSuiteConfig::AlphaCutoff) == TestSuiteConfig::AlphaCutoff; } - + bool TestSerialization() const { return (GetParam() & TestSuiteConfig::Serialize) == TestSuiteConfig::Serialize; } + omm::Cpu::Texture CreateTexture(const omm::Cpu::TextureDesc& desc) { omm::Cpu::Texture tex = 0; EXPECT_EQ(omm::Cpu::CreateTexture(_baker, desc, &tex), omm::Result::SUCCESS); @@ -110,6 +121,24 @@ namespace { } } + std::vector readFileData(const std::string& name) { + std::ifstream inputFile(name, std::ios_base::binary); + + // Determine the length of the file by seeking + // to the end of the file, reading the value of the + // position indicator, and then seeking back to the beginning. + inputFile.seekg(0, std::ios_base::end); + auto length = inputFile.tellg(); + inputFile.seekg(0, std::ios_base::beg); + + // Make a buffer of the exact size of the file and read the data into it. + std::vector buffer(length); + inputFile.read(reinterpret_cast(buffer.data()), length); + + inputFile.close(); + return buffer; + } + omm::Debug::Stats RunOmmBake( float alphaCutoff, uint32_t subdivisionLevel, @@ -119,7 +148,7 @@ namespace { omm::TexCoordFormat texCoordFormat, void* texCoords, omm::Cpu::Texture tex, - const Options opt = {}) + const Options opt = {}) { omm::Cpu::BakeInputDesc desc; desc.texture = tex; @@ -134,10 +163,11 @@ namespace { desc.indexCount = indexCount; desc.maxSubdivisionLevel = subdivisionLevel; desc.alphaCutoff = alphaCutoff; - desc.alphaCutoffLE = opt.alphaCutoffLE; - desc.alphaCutoffGT = opt.alphaCutoffGT; + desc.alphaCutoffLessEqual = opt.alphaCutoffLE; + desc.alphaCutoffGreater = opt.alphaCutoffGT; desc.unknownStatePromotion = opt.unknownStatePromotion; desc.bakeFlags = (omm::Cpu::BakeFlags)((uint32_t)omm::Cpu::BakeFlags::EnableInternalThreads); + desc.maxWorkloadSize = opt.maxWorkloadSize; if (opt.mergeSimilar) desc.bakeFlags = (omm::Cpu::BakeFlags)((uint32_t)desc.bakeFlags | (uint32_t)omm::Cpu::BakeFlags::EnableNearDuplicateDetection); @@ -148,15 +178,151 @@ namespace { desc.dynamicSubdivisionScale = 0.f; - omm::Cpu::BakeResult res = 0; + omm::Cpu::BakeResult res = nullptr; + const omm::Cpu::BakeResultDesc* resDesc = nullptr; + if (TestSerialization() || opt.forceCorruptedBlob) + { + std::vector data; + { + omm::Cpu::DeserializedDesc dataToSerialize; + dataToSerialize.numInputDescs = 1; + dataToSerialize.inputDescs = &desc; + + // Serialize... + omm::Cpu::SerializedResult serializedRes = 0; + EXPECT_EQ(omm::Cpu::Serialize(_baker, dataToSerialize, &serializedRes), omm::Result::SUCCESS); + EXPECT_NE(serializedRes, nullptr); - EXPECT_EQ(omm::Cpu::Bake(_baker, desc, &res), omm::Result::SUCCESS); - EXPECT_NE(res, 0); + // Get data blob + const omm::Cpu::BlobDesc* blob = nullptr; + EXPECT_EQ(omm::Cpu::GetSerializedResultDesc(serializedRes, &blob), omm::Result::SUCCESS); - const omm::Cpu::BakeResultDesc* resDesc = nullptr; - EXPECT_EQ(omm::Cpu::GetBakeResultDesc(res, &resDesc), omm::Result::SUCCESS); + // Copy content. + data = std::vector((uint8_t*)blob->data, (uint8_t*)blob->data + blob->size); + + // Destroy + EXPECT_EQ(omm::Cpu::DestroySerializedResult(serializedRes), omm::Result::SUCCESS); + } + + // Now do deserialize again and call bake + { + omm::Cpu::BlobDesc blob; + blob.data = data.data(); + blob.size = data.size(); + + if (opt.forceCorruptedBlob) + { + blob.size -= sizeof(uint32_t); + } + + omm::Cpu::DeserializedResult dRes = nullptr; + if (opt.forceCorruptedBlob) + { + EXPECT_EQ(omm::Cpu::Deserialize(_baker, blob, &dRes), omm::Result::INVALID_ARGUMENT); + return omm::Debug::Stats(); + } + else + { + EXPECT_EQ(omm::Cpu::Deserialize(_baker, blob, &dRes), omm::Result::SUCCESS); + } + + EXPECT_NE(dRes, nullptr); + + const omm::Cpu::DeserializedDesc* desDesc = nullptr; + EXPECT_EQ(omm::Cpu::GetDeserializedDesc(dRes, &desDesc), omm::Result::SUCCESS); + + EXPECT_EQ(desDesc->numInputDescs, 1); + EXPECT_EQ(desDesc->numResultDescs, 0); + + const omm::Cpu::BakeInputDesc& descCopy = desDesc->inputDescs[0]; + + EXPECT_EQ(omm::Cpu::Bake(_baker, descCopy, &res), opt.bakeResult); + + if (opt.bakeResult != omm::Result::SUCCESS) + { + return omm::Debug::Stats(); + } + + EXPECT_NE(res, nullptr); + + EXPECT_EQ(omm::Cpu::DestroyDeserializedResult(dRes), omm::Result::SUCCESS); + + EXPECT_EQ(omm::Cpu::GetBakeResultDesc(res, &resDesc), omm::Result::SUCCESS); + } + + // Now try serialize the bake results too! + { + omm::Cpu::DeserializedDesc dataToSerialize; + dataToSerialize.numResultDescs = 1; + dataToSerialize.resultDescs = resDesc; + + // Serialize... + omm::Cpu::SerializedResult serializedRes = 0; + EXPECT_EQ(omm::Cpu::Serialize(_baker, dataToSerialize, &serializedRes), omm::Result::SUCCESS); + EXPECT_NE(serializedRes, nullptr); + + // Get data blob + const omm::Cpu::BlobDesc* blob = nullptr; + EXPECT_EQ(omm::Cpu::GetSerializedResultDesc(serializedRes, &blob), omm::Result::SUCCESS); + + // Copy content. + data = std::vector((uint8_t*)blob->data, (uint8_t*)blob->data + blob->size); + + // Destroy + EXPECT_EQ(omm::Cpu::DestroySerializedResult(serializedRes), omm::Result::SUCCESS); + } + + // Now do deserialize & compare + { + omm::Cpu::BlobDesc blob; + blob.data = data.data(); + blob.size = data.size(); + + omm::Cpu::DeserializedResult dRes = nullptr; + EXPECT_EQ(omm::Cpu::Deserialize(_baker, blob, &dRes), omm::Result::SUCCESS); + EXPECT_NE(dRes, nullptr); + + const omm::Cpu::DeserializedDesc* desDesc = nullptr; + EXPECT_EQ(omm::Cpu::GetDeserializedDesc(dRes, &desDesc), omm::Result::SUCCESS); + + EXPECT_EQ(desDesc->numInputDescs, 0); + EXPECT_EQ(desDesc->numResultDescs, 1); + + const omm::Cpu::BakeResultDesc* resDescCpy = &desDesc->resultDescs[0]; + // Compare results + + EXPECT_EQ(resDesc->arrayDataSize, resDescCpy->arrayDataSize); + EXPECT_EQ(memcmp(resDesc->arrayData, resDescCpy->arrayData, resDesc->arrayDataSize), 0); + + EXPECT_EQ(resDesc->descArrayCount, resDescCpy->descArrayCount); + EXPECT_EQ(memcmp(resDesc->descArray, resDescCpy->descArray, sizeof(omm::Cpu::OpacityMicromapDesc) * resDesc->descArrayCount), 0); + + EXPECT_EQ(resDesc->descArrayHistogramCount, resDescCpy->descArrayHistogramCount); + EXPECT_EQ(memcmp(resDesc->descArrayHistogram, resDescCpy->descArrayHistogram, sizeof(omm::Cpu::OpacityMicromapUsageCount) * resDesc->descArrayHistogramCount), 0); + + EXPECT_EQ(resDesc->indexCount, resDescCpy->indexCount); + EXPECT_EQ(resDesc->indexFormat, resDescCpy->indexFormat); + EXPECT_EQ(memcmp(resDesc->indexBuffer, resDescCpy->indexBuffer, (resDescCpy->indexFormat == omm::IndexFormat::UINT_16 ? 2 : 4) * resDesc->indexCount), 0); + + EXPECT_EQ(resDesc->indexHistogramCount, resDescCpy->indexHistogramCount); + EXPECT_EQ(memcmp(resDesc->indexHistogram, resDescCpy->indexHistogram, sizeof(omm::Cpu::OpacityMicromapUsageCount)* resDesc->indexHistogramCount), 0); + + EXPECT_EQ(omm::Cpu::DestroyDeserializedResult(dRes), omm::Result::SUCCESS); + } + } + else + { + EXPECT_EQ(omm::Cpu::Bake(_baker, desc, &res), opt.bakeResult); + if (opt.bakeResult != omm::Result::SUCCESS) + { + return omm::Debug::Stats(); + } + + EXPECT_NE(res, nullptr); + + EXPECT_EQ(omm::Cpu::GetBakeResultDesc(res, &resDesc), omm::Result::SUCCESS); + } - #if OMM_TEST_ENABLE_IMAGE_DUMP constexpr bool kDumpDebug = true; #else @@ -325,7 +491,7 @@ namespace { return stats; } - omm::Debug::Stats LeafletLevelN(uint32_t subdivisionLevel) + omm::Debug::Stats LeafletLevelN(uint32_t subdivisionLevel, uint64_t maxWorkloadSize = 0xFFFFFFFFFFFFFFFF, omm::Result bakeResult = omm::Result::SUCCESS) { uint32_t numMicroTris = omm::bird::GetNumMicroTriangles(subdivisionLevel); @@ -353,12 +519,11 @@ namespace { return 1.f - mips[w * j + i]; - }, { .format = omm::Format::OC1_4_State, .unknownStatePromotion = omm::UnknownStatePromotion::Nearest, .enableSpecialIndices = false, .oneFile = true, .detailedCutout = false }); + }, { .format = omm::Format::OC1_4_State, .unknownStatePromotion = omm::UnknownStatePromotion::Nearest, .enableSpecialIndices = false, .oneFile = true, .detailedCutout = false, .maxWorkloadSize = maxWorkloadSize, .bakeResult = bakeResult }); return stats; } - std::vector< omm::Cpu::Texture> _textures; omm::Baker _baker = 0; }; @@ -366,9 +531,9 @@ namespace { TEST_P(OMMBakeTestCPU, NullDesc) { omm::Cpu::BakeInputDesc nullDesc; - omm::Cpu::BakeResult res = 0; + omm::Cpu::BakeResult res = nullptr; EXPECT_EQ(omm::Cpu::Bake(_baker, nullDesc, &res), omm::Result::INVALID_ARGUMENT); - EXPECT_EQ(res, 0); + EXPECT_EQ(res, nullptr); } TEST_P(OMMBakeTestCPU, AllOpaque4) { @@ -526,6 +691,18 @@ namespace { }); } + TEST_P(OMMBakeTestCPU, AllOpaque1_CorruptedBlob) { + + uint32_t subdivisionLevel = 1; + uint32_t numMicroTris = omm::bird::GetNumMicroTriangles(subdivisionLevel); + + omm::Debug::Stats stats = RunOmmBakeFP32(0.5f, subdivisionLevel, { 1024, 1024 }, [](int i, int j, int w, int h, int mip)->float { + return 0.6f; + }, { .bakeResult = omm::Result::INVALID_ARGUMENT, .forceCorruptedBlob = true }); + + ExpectEqual(stats, { .totalFullyOpaque = 0 }); + } + TEST_P(OMMBakeTestCPU, Circle) { uint32_t subdivisionLevel = 4; @@ -1622,6 +1799,18 @@ namespace { }); } + TEST_P(OMMBakeTestCPU, LeafletLevel12_TooBigWorkload) { + + omm::Debug::Stats stats = LeafletLevelN(12, 512, omm::Result::WORKLOAD_TOO_BIG); + + ExpectEqual(stats, { + .totalOpaque = 0, + .totalTransparent = 0, + .totalUnknownTransparent = 0, + .totalUnknownOpaque = 0, + }); + } + TEST_P(OMMBakeTestCPU, DestroyOpacityMicromapBaker) { } @@ -1653,11 +1842,12 @@ namespace { } INSTANTIATE_TEST_SUITE_P(OMMTestCPU, OMMBakeTestCPU, ::testing::Values( - TestSuiteConfig::Default - , TestSuiteConfig::TextureDisableZOrder - , TestSuiteConfig::Force32BitIndices - , TestSuiteConfig::TextureAsUNORM8 - , TestSuiteConfig::AlphaCutoff + TestSuiteConfig::Default + , TestSuiteConfig::TextureDisableZOrder + , TestSuiteConfig::Force32BitIndices + , TestSuiteConfig::TextureAsUNORM8 + , TestSuiteConfig::AlphaCutoff + , TestSuiteConfig::Serialize ), CustomParamName); diff --git a/tests/test_omm_bake_gpu.cpp b/tests/test_omm_bake_gpu.cpp index e6edafb..00d53da 100644 --- a/tests/test_omm_bake_gpu.cpp +++ b/tests/test_omm_bake_gpu.cpp @@ -193,8 +193,8 @@ namespace { input.alphaTexture = alphaTexture; input.alphaTextureChannel = alphaTextureChannel; input.alphaCutoff = p.alphaCutoff; - input.alphaCutoffLE = p.alphaCutoffLE; - input.alphaCutoffGT = p.alphaCutoffGT; + input.alphaCutoffLessEqual = p.alphaCutoffLE; + input.alphaCutoffGreater = p.alphaCutoffGT; input.texCoordFormat = p.texCoordFormat; input.texCoordBuffer = vb; input.texCoordStrideInBytes = 0; diff --git a/tests/test_omm_indexing.cpp b/tests/test_omm_indexing.cpp index 81a8903..e1c4064 100644 --- a/tests/test_omm_indexing.cpp +++ b/tests/test_omm_indexing.cpp @@ -97,7 +97,7 @@ namespace { EXPECT_EQ(omm::Cpu::Bake(_baker, desc, &res), expectedResult); if (expectedResult != omm::Result::SUCCESS) return; - EXPECT_NE(res, 0); + EXPECT_NE(res, nullptr); const omm::Cpu::BakeResultDesc* resDesc = nullptr; EXPECT_EQ(omm::Cpu::GetBakeResultDesc(res, &resDesc), omm::Result::SUCCESS); diff --git a/tests/test_omm_log.cpp b/tests/test_omm_log.cpp index 224b2aa..186915e 100644 --- a/tests/test_omm_log.cpp +++ b/tests/test_omm_log.cpp @@ -116,14 +116,14 @@ namespace { _expectedLogMsg = expectedLogMsg; _logCounter = 0; - omm::Cpu::BakeResult res = 0; + omm::Cpu::BakeResult res = nullptr; ASSERT_EQ(omm::Cpu::Bake(_baker, desc, &res), expectedResult); if (expectedResult != omm::Result::SUCCESS) return; - EXPECT_NE(res, 0); + EXPECT_NE(res, nullptr); const omm::Cpu::BakeResultDesc* resDesc = nullptr; EXPECT_EQ(omm::Cpu::GetBakeResultDesc(res, &resDesc), omm::Result::SUCCESS); @@ -177,10 +177,11 @@ namespace { { InitBaker(true /*set callback*/); omm::Cpu::BakeInputDesc desc = CreateDefaultBakeInputDesc(); - desc.alphaCutoffGT = omm::OpacityState::Opaque; - desc.alphaCutoffLE = omm::OpacityState::UnknownOpaque; + desc.alphaCutoffGreater = omm::OpacityState::Opaque; + desc.alphaCutoffLessEqual = omm::OpacityState::UnknownOpaque; desc.format = omm::Format::OC1_2_State; - Bake(desc, { "[Invalid Argument] - alphaCutoffLE=UnknownOpaque is not compatible with OC1_2_State" }, omm::Result::INVALID_ARGUMENT); + + Bake(desc, { "[Invalid Argument] - alphaCutoffLessEqual=UnknownOpaque is not compatible with OC1_2_State" }, omm::Result::INVALID_ARGUMENT); } TEST_F(LogTest, PerfWarning_HugeWorkload) diff --git a/tests/test_subdiv.cpp b/tests/test_subdiv.cpp index c75b9c3..72e11bf 100644 --- a/tests/test_subdiv.cpp +++ b/tests/test_subdiv.cpp @@ -160,10 +160,10 @@ namespace { ); desc.dynamicSubdivisionScale = 0.f; - omm::Cpu::BakeResult res = 0; + omm::Cpu::BakeResult res = nullptr; EXPECT_EQ(omm::Cpu::Bake(_baker, desc, &res), omm::Result::SUCCESS); - EXPECT_NE(res, 0); + EXPECT_NE(res, nullptr); const omm::Cpu::BakeResultDesc* resDesc = nullptr; EXPECT_EQ(omm::Cpu::GetBakeResultDesc(res, &resDesc), omm::Result::SUCCESS); diff --git a/thirdparty/CMakeLists.txt b/thirdparty/CMakeLists.txt index 9af1a3e..ac526e6 100644 --- a/thirdparty/CMakeLists.txt +++ b/thirdparty/CMakeLists.txt @@ -45,7 +45,7 @@ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/nvrhi) endif() # gtest -if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/gtest) +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/gtest AND OMM_ENABLE_TESTS) set(INSTALL_GTEST OFF) set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) add_subdirectory("gtest")