yum-mirror/slang

Making it easier to work with shaders

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

Gangzheng TongFix additional VVL violations (#7377)3822f9243

master
11.9 KiB358 linesraw
1// shader-renderer-util.cpp
2
3#include "shader-renderer-util.h"
4
5namespace renderer_test
6{
7
8using namespace Slang;
9using Slang::Result;
10
11inline int calcMipSize(int size, int level)
12{
13    size = size >> level;
14    return size > 0 ? size : 1;
15}
16
17inline Extent3D calcMipSize(Extent3D size, int mipLevel)
18{
19    Extent3D rs;
20    rs.width = calcMipSize(size.width, mipLevel);
21    rs.height = calcMipSize(size.height, mipLevel);
22    rs.depth = calcMipSize(size.depth, mipLevel);
23    return rs;
24}
25
26/// Given the type works out the maximum dimension size
27inline int calcMaxDimension(Extent3D size, TextureType type)
28{
29    switch (type)
30    {
31    case TextureType::Texture1D:
32        return size.width;
33    case TextureType::Texture3D:
34        return Math::Max(Math::Max(size.width, size.height), size.depth);
35    case TextureType::TextureCube: // fallthru
36    case TextureType::Texture2D:
37        {
38            return Math::Max(size.width, size.height);
39        }
40    default:
41        return 0;
42    }
43}
44
45/// Given the type, calculates the number of mip maps. 0 on error
46inline int calcNumMipLevels(TextureType type, Extent3D size)
47{
48    const int maxDimensionSize = calcMaxDimension(size, type);
49    return (maxDimensionSize > 0) ? (Math::Log2Floor(maxDimensionSize) + 1) : 0;
50}
51
52/* static */ Result ShaderRendererUtil::generateTexture(
53    const InputTextureDesc& inputDesc,
54    ResourceState defaultState,
55    IDevice* device,
56    ComPtr<ITexture>& textureOut)
57{
58    TextureData texData;
59    generateTextureData(texData, inputDesc);
60    return createTexture(inputDesc, texData, defaultState, device, textureOut);
61}
62
63/* static */ Result ShaderRendererUtil::createTexture(
64    const InputTextureDesc& inputDesc,
65    const TextureData& texData,
66    ResourceState defaultState,
67    IDevice* device,
68    ComPtr<ITexture>& textureOut)
69{
70    TextureDesc textureDesc = {};
71
72    // Default to RGBA8Unorm
73    const Format format =
74        (inputDesc.format == Format::Undefined) ? Format::RGBA8Unorm : inputDesc.format;
75
76    const FormatInfo& formatInfo = getFormatInfo(format);
77
78    bool isArray = inputDesc.arrayLength > 1;
79    bool isMS = inputDesc.sampleCount > 1;
80
81    textureDesc.sampleCount = inputDesc.sampleCount;
82    textureDesc.format = format;
83    textureDesc.mipCount = texData.m_mipLevels;
84    if (isArray)
85    {
86        textureDesc.arrayLength = inputDesc.arrayLength;
87    }
88    textureDesc.usage = TextureUsage::CopyDestination | TextureUsage::CopySource;
89    switch (defaultState)
90    {
91    case ResourceState::ShaderResource:
92        textureDesc.usage |= TextureUsage::ShaderResource;
93        break;
94    case ResourceState::UnorderedAccess:
95        textureDesc.usage |= TextureUsage::UnorderedAccess;
96        break;
97    default:
98        return SLANG_FAIL;
99    }
100    textureDesc.defaultState = defaultState;
101
102    // It's the same size in all dimensions
103    switch (inputDesc.dimension)
104    {
105    case 1:
106        {
107            textureDesc.type = isArray ? TextureType::Texture1DArray : TextureType::Texture1D;
108            textureDesc.size.width = inputDesc.size;
109            textureDesc.size.height = 1;
110            textureDesc.size.depth = 1;
111
112            break;
113        }
114    case 2:
115        {
116            textureDesc.type =
117                isArray
118                    ? (inputDesc.isCube
119                           ? TextureType::TextureCubeArray
120                           : (isMS ? TextureType::Texture2DMSArray : TextureType::Texture2DArray))
121                    : (inputDesc.isCube
122                           ? TextureType::TextureCube
123                           : (isMS ? TextureType::Texture2DMS : TextureType::Texture2D));
124            textureDesc.size.width = inputDesc.size;
125            textureDesc.size.height = inputDesc.size;
126            textureDesc.size.depth = 1;
127            break;
128        }
129    case 3:
130        {
131            textureDesc.type = TextureType::Texture3D;
132            textureDesc.size.width = inputDesc.size;
133            textureDesc.size.height = inputDesc.size;
134            textureDesc.size.depth = inputDesc.size;
135            break;
136        }
137    }
138
139    if (textureDesc.mipCount == 0)
140    {
141        textureDesc.mipCount = calcNumMipLevels(textureDesc.type, textureDesc.size);
142    }
143
144    // Metal doesn't support mip maps for 1D textures.
145    if ((isMS) || (device->getDeviceType() == DeviceType::Metal &&
146                   (textureDesc.type == TextureType::Texture1D ||
147                    textureDesc.type == TextureType::Texture1DArray)))
148    {
149        textureDesc.mipCount = 1;
150    }
151
152    List<SubresourceData> initSubresources;
153    int layerCount = textureDesc.getLayerCount();
154    int subResourceCounter = 0;
155    for (int a = 0; a < layerCount; ++a)
156    {
157        for (int m = 0; m < textureDesc.mipCount; ++m)
158        {
159            int subResourceIndex = subResourceCounter++;
160            const int mipWidth = calcMipSize(textureDesc.size.width, m);
161            const int mipHeight = calcMipSize(textureDesc.size.height, m);
162
163            size_t rowPitch = mipWidth * formatInfo.blockSizeInBytes;
164            size_t slicePitch = mipHeight * rowPitch;
165
166            SubresourceData subresourceData;
167            subresourceData.data = texData.m_slices[subResourceIndex].values;
168            subresourceData.rowPitch = rowPitch;
169            subresourceData.slicePitch = slicePitch;
170
171            initSubresources.add(subresourceData);
172        }
173    }
174
175    if (isMS)
176    {
177        textureDesc.usage |= TextureUsage::RenderTarget;
178        textureOut = device->createTexture(textureDesc);
179        clearTexture(textureOut.get(), inputDesc.content, device);
180    }
181    else
182    {
183        textureOut = device->createTexture(textureDesc, initSubresources.getBuffer());
184    }
185
186    return textureOut ? SLANG_OK : SLANG_FAIL;
187}
188
189/* static */ Result ShaderRendererUtil::createBuffer(
190    const InputBufferDesc& inputDesc,
191    size_t bufferSize,
192    const void* initData,
193    IDevice* device,
194    ComPtr<IBuffer>& bufferOut)
195{
196    BufferDesc bufferDesc;
197    bufferDesc.size = bufferSize;
198    bufferDesc.format = inputDesc.format;
199    bufferDesc.elementSize = inputDesc.stride;
200    bufferDesc.usage = BufferUsage::CopyDestination | BufferUsage::CopySource |
201                       BufferUsage::ShaderResource | BufferUsage::UnorderedAccess;
202    bufferDesc.defaultState = ResourceState::UnorderedAccess;
203
204    ComPtr<IBuffer> bufferResource = device->createBuffer(bufferDesc, initData);
205    if (!bufferResource)
206    {
207        return SLANG_FAIL;
208    }
209
210    bufferOut = bufferResource;
211    return SLANG_OK;
212}
213
214/* static */ Result ShaderRendererUtil::clearTexture(
215    ITexture* texture,
216    InputTextureContent content,
217    IDevice* device)
218{
219    SLANG_ASSERT(texture);
220    ComPtr<ICommandQueue> queue;
221    SLANG_RETURN_ON_FAIL(device->getQueue(QueueType::Graphics, queue.writeRef()));
222
223    ComPtr<ICommandEncoder> commandEncoder;
224    SLANG_RETURN_ON_FAIL(queue->createCommandEncoder(commandEncoder.writeRef()));
225
226    TextureDesc desc = texture->getDesc();
227    SubresourceRange range;
228    range.layer = 0;
229    range.layerCount = texture->getDesc().arrayLength;
230    range.mip = 0;
231    range.mipCount = texture->getDesc().mipCount;
232
233    FormatInfo formatInfo = getFormatInfo(desc.format);
234    switch (formatInfo.kind)
235    {
236    case FormatKind::Float:
237        {
238            float clearValue[4] = {0.0f, 0.0f, 0.0f, 0.0f};
239            switch (content)
240            {
241            case InputTextureContent::Zero:
242                // clearValue is already all zeros
243                break;
244            case InputTextureContent::One:
245                clearValue[0] = clearValue[1] = clearValue[2] = clearValue[3] = 1.0f;
246                break;
247            case InputTextureContent::ChessBoard:
248            case InputTextureContent::Gradient:
249                // For chessboard or gradient, we can't use a single clear value
250                // Instead, we should use a compute shader or multiple draw calls
251                SLANG_ASSERT(!"ChessBoard or Gradient content type is not supported for "
252                              "multisampled textures - requires compute shader implementation");
253                return SLANG_FAIL;
254            }
255            commandEncoder->clearTextureFloat(texture, range, clearValue);
256            break;
257        }
258    case FormatKind::Integer:
259        {
260            uint32_t clearValue[4] = {0U, 0U, 0U, 0U};
261            switch (content)
262            {
263            case InputTextureContent::Zero:
264                // clearValue is already all zeros
265                break;
266            case InputTextureContent::One:
267                clearValue[0] = clearValue[1] = clearValue[2] = clearValue[3] = 1U;
268                break;
269            case InputTextureContent::ChessBoard:
270            case InputTextureContent::Gradient:
271                // For chessboard or gradient, we can't use a single clear value
272                // Instead, we should use a compute shader or multiple draw calls
273                SLANG_ASSERT(!"ChessBoard or Gradient content type is not supported for "
274                              "multisampled textures - requires compute shader implementation");
275                return SLANG_FAIL;
276            }
277            commandEncoder->clearTextureUint(texture, range, clearValue);
278            break;
279        }
280    case FormatKind::Normalized:
281        {
282            int32_t clearValue[4] = {0, 0, 0, 0};
283            switch (content)
284            {
285            case InputTextureContent::Zero:
286                // clearValue is already all zeros
287                break;
288            case InputTextureContent::One:
289                clearValue[0] = clearValue[1] = clearValue[2] = clearValue[3] = 1;
290                break;
291            case InputTextureContent::ChessBoard:
292            case InputTextureContent::Gradient:
293                // For chessboard or gradient, we can't use a single clear value
294                // Instead, we should use a compute shader or multiple draw calls
295                SLANG_ASSERT(!"ChessBoard or Gradient content type is not supported for "
296                              "multisampled textures - requires compute shader implementation");
297                return SLANG_FAIL;
298            }
299            commandEncoder->clearTextureSint(texture, range, clearValue);
300            break;
301        }
302    case FormatKind::DepthStencil:
303        {
304            float depthValue = 0.f;
305            uint8_t stencilValue = 0U;
306            switch (content)
307            {
308            case InputTextureContent::Zero:
309                // clearValue is already all zeros
310                break;
311            case InputTextureContent::One:
312                depthValue = 1;
313                stencilValue = 1U;
314                break;
315            case InputTextureContent::ChessBoard:
316            case InputTextureContent::Gradient:
317                // For chessboard or gradient, we can't use a single clear value
318                // Instead, we should use a compute shader or multiple draw calls
319                SLANG_ASSERT(!"ChessBoard or Gradient content type is not supported for "
320                              "multisampled textures - requires compute shader implementation");
321                return SLANG_FAIL;
322            }
323            commandEncoder
324                ->clearTextureDepthStencil(texture, range, true, depthValue, true, stencilValue);
325            break;
326        }
327    default:
328        {
329            SLANG_ASSERT(!"Unsupported FormatKind type");
330            return SLANG_FAIL;
331        }
332    }
333
334    SLANG_RETURN_ON_FAIL(queue->submit(commandEncoder->finish()));
335
336    return SLANG_OK;
337}
338
339static SamplerDesc _calcSamplerDesc(const InputSamplerDesc& srcDesc)
340{
341    SamplerDesc samplerDesc;
342    if (srcDesc.isCompareSampler)
343    {
344        samplerDesc.reductionOp = TextureReductionOp::Comparison;
345        samplerDesc.comparisonFunc = ComparisonFunc::Less;
346    }
347    samplerDesc.minFilter = srcDesc.filteringMode;
348    samplerDesc.magFilter = srcDesc.filteringMode;
349    samplerDesc.mipFilter = srcDesc.filteringMode;
350    return samplerDesc;
351}
352
353ComPtr<ISampler> _createSampler(IDevice* device, const InputSamplerDesc& srcDesc)
354{
355    return device->createSampler(_calcSamplerDesc(srcDesc));
356}
357
358} // namespace renderer_test