Resource.h 4.31 KB
Newer Older
Nianchen Deng's avatar
Nianchen Deng committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#pragma once
#include <map>
#include <vector>

class Resource {
public:
    virtual ~Resource() {}

    virtual void *getBuffer() const = 0;

    virtual size_t size() const = 0;
};

class CudaBuffer : public Resource {
public:
    CudaBuffer(void *buffer = nullptr, size_t size = 0)
        : _buffer(buffer), _ownBuffer(false), _size(size) {}
    CudaBuffer(size_t size) : _buffer(nullptr), _ownBuffer(true), _size(size) {
        CHECK_EX(cudaMalloc(&_buffer, size));
    }
    CudaBuffer(const CudaBuffer &rhs) = delete;

    virtual ~CudaBuffer() {
        if (!_ownBuffer || _buffer == nullptr)
            return;
        try {
            CHECK_EX(cudaFree(_buffer));
        } catch (std::exception &ex) {
            Logger::instance.warning(std::string("Exception raised in destructor: ") + ex.what());
        }
        _buffer = nullptr;
        _ownBuffer = false;
    }

    virtual void *getBuffer() const { return _buffer; }
    template <class T> T *getBuffer() const { return (T *)getBuffer(); }

    virtual size_t size() const { return _size; }

private:
    void *_buffer;
    bool _ownBuffer;
    size_t _size;
};

template <typename T> class CudaArray : public CudaBuffer {
public:
    CudaArray(size_t n) : CudaBuffer(n * sizeof(T)) {}
    CudaArray(T *buffer, size_t n) : CudaBuffer(buffer, n * sizeof(T)) {}
    CudaArray(const std::vector<T> &hostArray) : CudaBuffer(hostArray.size() * sizeof(T)) {
        cudaMemcpy(getBuffer(), hostArray.data(), size(), cudaMemcpyHostToDevice);
    }
    CudaArray(const CudaArray<T> &rhs) = delete;

    size_t n() const { return size() / sizeof(T); }

    operator T *() { return (T *)getBuffer(); }
    CudaArray<T> *subArray(size_t offset, size_t n = -1) {
        if (n == -1)
            n = this->n() - offset;
        return new CudaArray<T>(*this + offset, n);
    }
};

class GraphicsResource : public Resource {
public:
    cudaGraphicsResource_t getHandler() { return _res; }

    virtual ~GraphicsResource() {
        if (_res == nullptr)
            return;
        try {
            CHECK_EX(cudaGraphicsUnregisterResource(_res));
        } catch (std::exception &ex) {
            Logger::instance.warning(std::string("Exception raised in destructor: ") + ex.what());
        }
        _res = nullptr;
    }

    virtual size_t size() const { return _size; }

protected:
    cudaGraphicsResource_t _res;
    size_t _size;

    GraphicsResource() : _res(nullptr), _size(0) {}
};

template <typename T> class GlTextureResource : public GraphicsResource {
public:
    GlTextureResource(GLuint textureID, glm::uvec2 textureSize) {
        CHECK_EX(cudaGraphicsGLRegisterImage(&_res, textureID, GL_TEXTURE_2D,
                                             cudaGraphicsRegisterFlagsWriteDiscard));
        _size = textureSize.x * textureSize.y * sizeof(T);
        _textureSize = textureSize;
    }

    virtual ~GlTextureResource() { cudaGraphicsUnmapResources(1, &_res, 0); }

    virtual void *getBuffer() const {
        cudaArray_t buffer;
        try {
            CHECK_EX(cudaGraphicsSubResourceGetMappedArray(&buffer, _res, 0, 0));
        } catch (...) {
            return nullptr;
        }
        return buffer;
    }

    operator T *() { return (T *)getBuffer(); }

    glm::uvec2 textureSize() { return _textureSize; }

private:
    glm::uvec2 _textureSize;
};

class Resources {
public:
    std::map<std::string, Resource *> resources;
    std::vector<cudaGraphicsResource_t> graphicsResources;

    void addResource(const std::string &name, Resource *res) {
        auto gres = dynamic_cast<GraphicsResource *>(res);
        if (gres != nullptr)
            graphicsResources.push_back(gres->getHandler());
        resources[name] = res;
    }

    void clear() {
        resources.clear();
        graphicsResources.clear();
    }
};

template <typename T, typename T2 = T>
void dumpArray(std::ostream &so, CudaArray<T> &arr, size_t maxDumpRows = 0,
               size_t elemsPerRow = 1) {
    int chns = sizeof(T) / sizeof(T2);
    T2 *hostArr = new T2[arr.n() * chns];
    cudaMemcpy(hostArr, arr.getBuffer(), arr.n() * sizeof(T), cudaMemcpyDeviceToHost);
    dumpHostBuffer<T2>(so, hostArr, arr.n() * sizeof(T), chns * elemsPerRow, maxDumpRows);
    delete[] hostArr;
}