// Microsoft-ABI access to NVSDK_NGX_Parameter objects for MinGW-built code. // NVSDK_NGX_Parameter is a C++ interface with overloaded virtual Set/Get // methods; MSVC orders overloaded virtuals differently from the Itanium ABI, // so calls must be compiled with clang-cl. Build freestanding (/Zl /GS-). using D4rNgxResult = unsigned int; struct ID3D11Resource; struct ID3D12Resource; struct D4rNgxParameterAbi { virtual void Set(const char* name, unsigned long long value) = 0; virtual void Set(const char* name, float value) = 0; virtual void Set(const char* name, double value) = 0; virtual void Set(const char* name, unsigned int value) = 0; virtual void Set(const char* name, int value) = 0; virtual void Set(const char* name, ID3D11Resource* value) = 0; virtual void Set(const char* name, ID3D12Resource* value) = 0; virtual void Set(const char* name, void* value) = 0; virtual D4rNgxResult Get(const char* name, unsigned long long* value) const = 0; virtual D4rNgxResult Get(const char* name, float* value) const = 0; virtual D4rNgxResult Get(const char* name, double* value) const = 0; virtual D4rNgxResult Get(const char* name, unsigned int* value) const = 0; virtual D4rNgxResult Get(const char* name, int* value) const = 0; virtual D4rNgxResult Get(const char* name, ID3D11Resource** value) const = 0; virtual D4rNgxResult Get(const char* name, ID3D12Resource** value) const = 0; virtual D4rNgxResult Get(const char* name, void** value) const = 0; virtual void Reset() = 0; }; static D4rNgxParameterAbi* parameters(void* raw) { return static_cast(raw); } extern "C" void d4r_ngx_set_ull(void* raw, const char* name, unsigned long long value) { parameters(raw)->Set(name, value); } extern "C" void d4r_ngx_set_float(void* raw, const char* name, float value) { parameters(raw)->Set(name, value); } extern "C" void d4r_ngx_set_uint(void* raw, const char* name, unsigned int value) { parameters(raw)->Set(name, value); } extern "C" void d4r_ngx_set_int(void* raw, const char* name, int value) { parameters(raw)->Set(name, value); } extern "C" void d4r_ngx_set_void(void* raw, const char* name, void* value) { parameters(raw)->Set(name, value); } extern "C" D4rNgxResult d4r_ngx_get_ull(void* raw, const char* name, unsigned long long* value) { return parameters(raw)->Get(name, value); } extern "C" D4rNgxResult d4r_ngx_get_float(void* raw, const char* name, float* value) { return parameters(raw)->Get(name, value); } extern "C" D4rNgxResult d4r_ngx_get_uint(void* raw, const char* name, unsigned int* value) { return parameters(raw)->Get(name, value); } extern "C" D4rNgxResult d4r_ngx_get_int(void* raw, const char* name, int* value) { return parameters(raw)->Get(name, value); } extern "C" D4rNgxResult d4r_ngx_get_void(void* raw, const char* name, void** value) { return parameters(raw)->Get(name, value); } extern "C" D4rNgxResult d4r_ngx_get_d3d12_resource(void* raw, const char* name, ID3D12Resource** value) { return parameters(raw)->Get(name, value); } extern "C" void d4r_ngx_set_d3d12_resource(void* raw, const char* name, ID3D12Resource* value) { parameters(raw)->Set(name, value); } // A complete NVSDK_NGX_Parameter implementation handed out by the shim's // Allocate/Get/GetCapabilityParameters. It stores D3D12 resources (which the // CUDA-path parameter objects of the official core do not) and converts // between numeric types on Get, like the official implementations. inline void* operator new(decltype(sizeof(0)), void* place) noexcept { return place; } extern "C" void* d4r_host_alloc(unsigned long long size); // zero-filled, provided by the shim extern "C" void d4r_host_free(void* pointer); namespace { constexpr D4rNgxResult kSuccess = 0x1; constexpr D4rNgxResult kUnsupportedParameter = 0xBAD00010; enum ValueType : unsigned { TypeULL = 1, TypeFloat, TypeDouble, TypeUInt, TypeInt, TypePointer }; struct Entry { char name[96]; unsigned type; union { unsigned long long u; long long i; double d; void* p; } value; }; bool same_name(const char* a, const char* b) { for (; *a != 0 && *a == *b; ++a, ++b) { } return *a == *b; } class Parameters final : public D4rNgxParameterAbi { public: void Set(const char* name, unsigned long long value) override { store(name, TypeULL)->value.u = value; } void Set(const char* name, float value) override { store(name, TypeFloat)->value.d = value; } void Set(const char* name, double value) override { store(name, TypeDouble)->value.d = value; } void Set(const char* name, unsigned int value) override { store(name, TypeUInt)->value.u = value; } void Set(const char* name, int value) override { store(name, TypeInt)->value.i = value; } void Set(const char* name, ID3D11Resource* value) override { store(name, TypePointer)->value.p = value; } void Set(const char* name, ID3D12Resource* value) override { store(name, TypePointer)->value.p = value; } void Set(const char* name, void* value) override { store(name, TypePointer)->value.p = value; } D4rNgxResult Get(const char* name, unsigned long long* value) const override { return number(name, value); } D4rNgxResult Get(const char* name, float* value) const override { return number(name, value); } D4rNgxResult Get(const char* name, double* value) const override { return number(name, value); } D4rNgxResult Get(const char* name, unsigned int* value) const override { return number(name, value); } D4rNgxResult Get(const char* name, int* value) const override { return number(name, value); } D4rNgxResult Get(const char* name, ID3D11Resource** value) const override { return pointer(name, value); } D4rNgxResult Get(const char* name, ID3D12Resource** value) const override { return pointer(name, value); } D4rNgxResult Get(const char* name, void** value) const override { return pointer(name, value); } void Reset() override { count_ = 0; } private: const Entry* find(const char* name) const { for (unsigned index = 0; index < count_; ++index) if (same_name(entries_[index].name, name)) return &entries_[index]; return nullptr; } Entry* store(const char* name, unsigned type) { Entry* entry = const_cast(find(name)); if (entry == nullptr) { // Past capacity the last slot is reused rather than failing. entry = &entries_[count_ < kCapacity ? count_++ : kCapacity - 1]; unsigned length = 0; for (; name[length] != 0 && length + 1 < sizeof(entry->name); ++length) entry->name[length] = name[length]; entry->name[length] = 0; } entry->type = type; entry->value.u = 0; return entry; } template D4rNgxResult number(const char* name, T* value) const { const Entry* entry = find(name); if (entry == nullptr || value == nullptr) return kUnsupportedParameter; switch (entry->type) { case TypeFloat: case TypeDouble: *value = static_cast(entry->value.d); break; case TypeInt: *value = static_cast(entry->value.i); break; case TypePointer: *value = static_cast(reinterpret_cast(entry->value.p)); break; default: *value = static_cast(entry->value.u); break; } return kSuccess; } template D4rNgxResult pointer(const char* name, T** value) const { const Entry* entry = find(name); if (entry == nullptr || value == nullptr) return kUnsupportedParameter; *value = entry->type == TypePointer ? static_cast(entry->value.p) : reinterpret_cast(entry->value.u); return kSuccess; } static constexpr unsigned kCapacity = 256; unsigned count_ = 0; Entry entries_[kCapacity]; }; } // namespace extern "C" void* d4r_ngx_parameters_create() { void* memory = d4r_host_alloc(sizeof(Parameters)); return memory != nullptr ? static_cast(new (memory) Parameters()) : nullptr; } extern "C" void d4r_ngx_parameters_destroy(void* parameters) { d4r_host_free(parameters); }