yum-mirror/slang

Making it easier to work with shaders

git clone https://git.yummers.dev/yum-mirror/slang

Ellie Hermaszewskaformatf65d756bf

master
5.4 KiB188 linesraw
1// cpu-resource-views.cpp
2#include "cpu-resource-views.h"
3
4namespace gfx
5{
6using namespace Slang;
7
8namespace cpu
9{
10
11ResourceViewImpl::ResourceViewImpl(Kind kind, Desc const& desc)
12    : m_kind(kind)
13{
14    m_desc = desc;
15}
16
17BufferResourceImpl* BufferResourceViewImpl::getBuffer() const
18{
19    return m_buffer;
20}
21
22TextureResourceImpl* TextureResourceViewImpl::getTexture() const
23{
24    return m_texture;
25}
26
27slang_prelude::TextureDimensions TextureResourceViewImpl::GetDimensions(int mipLevel)
28{
29    slang_prelude::TextureDimensions dimensions = {};
30
31    TextureResourceImpl* texture = m_texture;
32    auto& desc = texture->_getDesc();
33    auto baseShape = texture->m_baseShape;
34
35    dimensions.arrayElementCount = desc.arraySize;
36    dimensions.numberOfLevels = desc.numMipLevels;
37    dimensions.shape = baseShape->rank;
38    dimensions.width = desc.size.width;
39    dimensions.height = desc.size.height;
40    dimensions.depth = desc.size.depth;
41
42    return dimensions;
43}
44
45void TextureResourceViewImpl::Load(const int32_t* texelCoords, void* outData, size_t dataSize)
46{
47    void* texelPtr = _getTexelPtr(texelCoords);
48
49    m_texture->m_formatInfo->unpackFunc(texelPtr, outData, dataSize);
50}
51
52void TextureResourceViewImpl::Sample(
53    slang_prelude::SamplerState samplerState,
54    const float* coords,
55    void* outData,
56    size_t dataSize)
57{
58    // We have no access to information from fragment quads, so we cannot
59    // compute the finite-difference derivatives needed from `coords`.
60    //
61    // The only reasonable thing to do is to sample mip level zero.
62    //
63    SampleLevel(samplerState, coords, 0.0f, outData, dataSize);
64}
65
66void TextureResourceViewImpl::SampleLevel(
67    slang_prelude::SamplerState samplerState,
68    const float* coords,
69    float level,
70    void* outData,
71    size_t dataSize)
72{
73    TextureResourceImpl* texture = m_texture;
74    auto baseShape = texture->m_baseShape;
75    auto& desc = texture->_getDesc();
76    int32_t rank = baseShape->rank;
77    int32_t baseCoordCount = baseShape->baseCoordCount;
78
79    int32_t integerMipLevel = int32_t(level + 0.5f);
80    if (integerMipLevel >= desc.numMipLevels)
81        integerMipLevel = desc.numMipLevels - 1;
82    if (integerMipLevel < 0)
83        integerMipLevel = 0;
84
85    auto& mipLevelInfo = texture->m_mipLevels[integerMipLevel];
86
87    bool isArray = (desc.arraySize != 0) || (desc.type == ITextureResource::Type::TextureCube);
88    int32_t effectiveArrayElementCount = texture->m_effectiveArrayElementCount;
89    int32_t coordIndex = baseCoordCount;
90    int32_t elementIndex = 0;
91    if (isArray)
92    {
93        elementIndex = int32_t(coords[coordIndex++] + 0.5f);
94    }
95    if (elementIndex >= effectiveArrayElementCount)
96        elementIndex = effectiveArrayElementCount - 1;
97    if (elementIndex < 0)
98        elementIndex = 0;
99
100    // Note: for now we are just going to do nearest-neighbor sampling
101    //
102    int64_t texelOffset = mipLevelInfo.offset;
103    texelOffset += elementIndex * mipLevelInfo.strides[3];
104    for (int32_t axis = 0; axis < rank; ++axis)
105    {
106        int32_t extent = mipLevelInfo.extents[axis];
107
108        float coord = coords[axis];
109
110        // TODO: deal with wrap/clamp/repeat if `coord < 0` or `coord > 1`
111
112        int32_t integerCoord = int32_t(coord * (extent - 1) + 0.5f);
113
114        if (integerCoord >= extent)
115            integerCoord = extent - 1;
116        if (integerCoord < 0)
117            integerCoord = 0;
118
119        texelOffset += integerCoord * mipLevelInfo.strides[axis];
120    }
121
122    auto texelPtr = (char const*)texture->m_data + texelOffset;
123
124    m_texture->m_formatInfo->unpackFunc(texelPtr, outData, dataSize);
125}
126
127void* TextureResourceViewImpl::refAt(const uint32_t* texelCoords)
128{
129    return _getTexelPtr((int32_t const*)texelCoords);
130}
131
132void* TextureResourceViewImpl::_getTexelPtr(int32_t const* texelCoords)
133{
134    TextureResourceImpl* texture = m_texture;
135    auto baseShape = texture->m_baseShape;
136    auto& desc = texture->_getDesc();
137
138    int32_t rank = baseShape->rank;
139    int32_t baseCoordCount = baseShape->baseCoordCount;
140
141    bool isArray = (desc.arraySize != 0) || (desc.type == ITextureResource::Type::TextureCube);
142    bool isMultisample = desc.sampleDesc.numSamples > 1;
143    bool isBuffer = desc.type == ITextureResource::Type::Buffer;
144    bool hasMipLevels = !(isMultisample || isBuffer);
145
146    int32_t effectiveArrayElementCount = texture->m_effectiveArrayElementCount;
147
148    int32_t coordIndex = baseCoordCount;
149    int32_t elementIndex = 0;
150    if (isArray)
151    {
152        elementIndex = texelCoords[coordIndex++];
153    }
154    if (elementIndex >= effectiveArrayElementCount)
155        elementIndex = effectiveArrayElementCount - 1;
156    if (elementIndex < 0)
157        elementIndex = 0;
158
159    int32_t mipLevel = 0;
160    if (!hasMipLevels)
161    {
162        mipLevel = texelCoords[coordIndex++];
163    }
164    if (mipLevel >= desc.numMipLevels)
165        mipLevel = desc.numMipLevels - 1;
166    if (mipLevel < 0)
167        mipLevel = 0;
168
169    auto& mipLevelInfo = texture->m_mipLevels[mipLevel];
170
171    int64_t texelOffset = mipLevelInfo.offset;
172    texelOffset += elementIndex * mipLevelInfo.strides[3];
173    for (int32_t axis = 0; axis < rank; ++axis)
174    {
175        int32_t coord = texelCoords[axis];
176        if (coord >= mipLevelInfo.extents[axis])
177            coord = mipLevelInfo.extents[axis] - 1;
178        if (coord < 0)
179            coord = 0;
180
181        texelOffset += texelCoords[axis] * mipLevelInfo.strides[axis];
182    }
183
184    return (char*)texture->m_data + texelOffset;
185}
186
187} // namespace cpu
188} // namespace gfx