yum-mirror/slang

Making it easier to work with shaders

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

Ellie HermaszewskaDisallow only resources in constant buffers in parameterblocks on metal (#6342)1ea2ab1b6

master
4.5 KiB133 linesraw
1// unit-test-ptr-layout.cpp
2
3#include "slang-com-ptr.h"
4#include "slang.h"
5#include "unit-test/slang-unit-test.h"
6
7#include <stdlib.h>
8
9using namespace Slang;
10
11SLANG_UNIT_TEST(metalConstantBufferInParameterBlockLayout)
12{
13    const char* testSource = R"(
14        struct T 
15        {
16            float4 m0;
17            float m1;
18            float3 m2;
19        };
20
21        ParameterBlock<ConstantBuffer<T>> params;
22    )";
23
24    ComPtr<slang::IGlobalSession> globalSession;
25    SLANG_CHECK(slang_createGlobalSession(SLANG_API_VERSION, globalSession.writeRef()) == SLANG_OK);
26
27    slang::TargetDesc targetDesc = {};
28    targetDesc.format = SLANG_METAL;
29    targetDesc.profile = globalSession->findProfile("metal");
30
31    slang::SessionDesc sessionDesc = {};
32    sessionDesc.targetCount = 1;
33    sessionDesc.targets = &targetDesc;
34
35    ComPtr<slang::ISession> session;
36    SLANG_CHECK(globalSession->createSession(sessionDesc, session.writeRef()) == SLANG_OK);
37
38    ComPtr<slang::IBlob> diagnosticBlob;
39    auto module = session->loadModuleFromSourceString(
40        "test",
41        "test.slang",
42        testSource,
43        diagnosticBlob.writeRef());
44    SLANG_CHECK(module != nullptr);
45
46    auto testBody = [&]()
47    {
48        auto reflection = module->getLayout();
49
50        // Collect our layouts
51        auto paramBlockType = reflection->findTypeByName("ParameterBlock<ConstantBuffer<T>>");
52        SLANG_CHECK(paramBlockType != nullptr);
53        auto paramBlockLayout = reflection->getTypeLayout(paramBlockType);
54        SLANG_CHECK(paramBlockLayout != nullptr);
55        auto cbufferLayout = paramBlockLayout->getElementTypeLayout();
56        SLANG_CHECK(cbufferLayout != nullptr);
57        auto structLayout = cbufferLayout->getElementTypeLayout();
58        SLANG_CHECK(structLayout != nullptr);
59
60        // Check offsets follow constant buffer rules (uniform alignment)
61        // m0 : float4 should be at offset 0
62        // m1 : float  should be at offset 16 (after float4)
63        // m2 : float3 should be at offset 32 (aligned to 16-byte boundary)
64        SLANG_CHECK(structLayout->getFieldCount() == 3);
65        SLANG_CHECK(structLayout->getFieldByIndex(0)->getOffset() == 0);
66        SLANG_CHECK(structLayout->getFieldByIndex(1)->getOffset() == 16);
67        SLANG_CHECK(structLayout->getFieldByIndex(2)->getOffset() == 32);
68    };
69
70    testBody();
71}
72
73SLANG_UNIT_TEST(metalArgumentBufferLayout)
74{
75    const char* testSource = R"(
76        struct T 
77        {
78            float4 m0;
79            float m1;
80            float3 m2;
81        };
82
83        // Using ParameterBlock directly without ConstantBuffer wrapper
84        ParameterBlock<T> params;
85    )";
86
87    ComPtr<slang::IGlobalSession> globalSession;
88    SLANG_CHECK(slang_createGlobalSession(SLANG_API_VERSION, globalSession.writeRef()) == SLANG_OK);
89
90    slang::TargetDesc targetDesc = {};
91    targetDesc.format = SLANG_METAL;
92    targetDesc.profile = globalSession->findProfile("metal");
93
94    slang::SessionDesc sessionDesc = {};
95    sessionDesc.targetCount = 1;
96    sessionDesc.targets = &targetDesc;
97
98    ComPtr<slang::ISession> session;
99    SLANG_CHECK(globalSession->createSession(sessionDesc, session.writeRef()) == SLANG_OK);
100
101    ComPtr<slang::IBlob> diagnosticBlob;
102    auto module = session->loadModuleFromSourceString(
103        "test",
104        "test.slang",
105        testSource,
106        diagnosticBlob.writeRef());
107    SLANG_CHECK(module != nullptr);
108
109    auto testBody = [&]()
110    {
111        auto reflection = module->getLayout();
112
113        // Collect our layouts
114        auto paramBlockType = reflection->findTypeByName("ParameterBlock<T>");
115        SLANG_CHECK(paramBlockType != nullptr);
116        auto paramBlockLayout = reflection->getTypeLayout(paramBlockType);
117        SLANG_CHECK(paramBlockLayout != nullptr);
118        auto structLayout = paramBlockLayout->getElementTypeLayout();
119        SLANG_CHECK(structLayout != nullptr);
120
121        // Check that offsets follow Metal argument buffer rules
122        // Fields should have 0 offset and meaningful binding indices
123        SLANG_CHECK(structLayout->getFieldCount() == 3);
124        SLANG_CHECK(structLayout->getFieldByIndex(0)->getOffset() == 0);
125        SLANG_CHECK(structLayout->getFieldByIndex(1)->getOffset() == 0);
126        SLANG_CHECK(structLayout->getFieldByIndex(2)->getOffset() == 0);
127        SLANG_CHECK(structLayout->getFieldByIndex(0)->getBindingIndex() == 0);
128        SLANG_CHECK(structLayout->getFieldByIndex(1)->getBindingIndex() == 1);
129        SLANG_CHECK(structLayout->getFieldByIndex(2)->getBindingIndex() == 2);
130    };
131
132    testBody();
133}