1/*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "shader_manager.h"
17
18#include <algorithm>
19#include <cinttypes>
20#include <cstring>
21
22#include <base/containers/array_view.h>
23#include <core/io/intf_file_manager.h>
24#include <render/device/gpu_resource_desc.h>
25#include <render/device/pipeline_layout_desc.h>
26#include <render/namespace.h>
27
28#include "device/device.h"
29#include "device/gpu_program.h"
30#include "device/gpu_program_util.h"
31#include "device/gpu_resource_handle_util.h"
32#include "device/shader_module.h"
33#include "device/shader_pipeline_binder.h"
34#include "loader/shader_loader.h"
35#include "resource_handle_impl.h"
36#include "util/log.h"
37
38using namespace BASE_NS;
39using namespace CORE_NS;
40
41constexpr uint64_t IA_HASH_PRIMITIVE_TOPOLOGY_SHIFT = 1;
42
43constexpr uint64_t RS_HASH_POLYGON_MODE_SHIFT = 4;
44constexpr uint64_t RS_HASH_CULL_MODE_SHIFT = 8;
45constexpr uint64_t RS_HASH_FRONT_FACE_SHIFT = 12;
46
47constexpr uint64_t DSS_HASH_DEPTH_COMPARE_SHIFT = 4;
48
49constexpr uint64_t HASH_RS_SHIFT = 0;
50constexpr uint64_t HASH_DS_SHIFT = 32;
51constexpr uint64_t HASH_IA_SHIFT = 56;
52
53union FloatAsUint32 {
54    float f;
55    uint32_t ui;
56};
57
58template<>
59uint64_t BASE_NS::hash(const RENDER_NS::GraphicsState::InputAssembly& inputAssembly)
60{
61    uint64_t hash = 0;
62    hash |= static_cast<uint64_t>(inputAssembly.enablePrimitiveRestart);
63    hash |= (static_cast<uint64_t>(inputAssembly.primitiveTopology) << IA_HASH_PRIMITIVE_TOPOLOGY_SHIFT);
64    return hash;
65}
66
67template<>
68uint64_t BASE_NS::hash(const RENDER_NS::GraphicsState::RasterizationState& state)
69{
70    uint64_t hash = 0;
71    hash |= (static_cast<uint64_t>(state.enableRasterizerDiscard) << 2u) |
72            (static_cast<uint64_t>(state.enableDepthBias) << 1u) | static_cast<uint64_t>(state.enableDepthClamp);
73    hash |= (static_cast<uint64_t>(state.polygonMode) << RS_HASH_POLYGON_MODE_SHIFT);
74    hash |= (static_cast<uint64_t>(state.cullModeFlags) << RS_HASH_CULL_MODE_SHIFT);
75    hash |= (static_cast<uint64_t>(state.frontFace) << RS_HASH_FRONT_FACE_SHIFT);
76    return hash;
77}
78
79template<>
80uint64_t BASE_NS::hash(const RENDER_NS::GraphicsState::DepthStencilState& state)
81{
82    uint64_t hash = 0;
83    hash |= (static_cast<uint64_t>(state.enableStencilTest) << 3u) |
84            (static_cast<uint64_t>(state.enableDepthBoundsTest) << 2u) |
85            (static_cast<uint64_t>(state.enableDepthWrite) << 1u) | static_cast<uint64_t>(state.enableDepthTest);
86    hash |= (static_cast<uint64_t>(state.depthCompareOp) << DSS_HASH_DEPTH_COMPARE_SHIFT);
87    return hash;
88}
89
90template<>
91uint64_t BASE_NS::hash(const RENDER_NS::GraphicsState::ColorBlendState::Attachment& state)
92{
93    uint64_t hash = 0;
94    hash |= (static_cast<uint64_t>(state.enableBlend) << 0u);
95    // blend factor values 0 - 18, 0x1f for exact (5 bits)
96    hash |= (static_cast<uint64_t>(state.srcColorBlendFactor) << 1u);
97    hash |= ((static_cast<uint64_t>(state.dstColorBlendFactor) & 0x1f) << 6u);
98    hash |= ((static_cast<uint64_t>(state.srcAlphaBlendFactor) & 0x1f) << 12u);
99    hash |= ((static_cast<uint64_t>(state.dstAlphaBlendFactor) & 0x1f) << 18u);
100    // blend op values 0 - 4, 0x7 for exact (3 bits)
101    hash |= ((static_cast<uint64_t>(state.colorBlendOp) & 0x7) << 24u);
102    hash |= ((static_cast<uint64_t>(state.alphaBlendOp) & 0x7) << 28u);
103    return hash;
104}
105
106template<>
107uint64_t BASE_NS::hash(const RENDER_NS::GraphicsState::ColorBlendState& state)
108{
109    uint64_t hash = 0;
110    hash |= (static_cast<uint64_t>(state.enableLogicOp) << 0u);
111    hash |= (static_cast<uint64_t>(state.logicOp) << 1u);
112
113    FloatAsUint32 vec[4u] = { { state.colorBlendConstants[0u] }, { state.colorBlendConstants[1u] },
114        { state.colorBlendConstants[2u] }, { state.colorBlendConstants[3u] } };
115    const uint64_t hashRG = (static_cast<uint64_t>(vec[0u].ui) << 32) | (vec[1u].ui);
116    const uint64_t hashBA = (static_cast<uint64_t>(vec[2u].ui) << 32) | (vec[3u].ui);
117    HashCombine(hash, hashRG, hashBA);
118    for (uint32_t idx = 0; idx < state.colorAttachmentCount; ++idx) {
119        HashCombine(hash, state.colorAttachments[idx]);
120    }
121    return hash;
122}
123
124template<>
125uint64_t BASE_NS::hash(const RENDER_NS::GraphicsState& state)
126{
127    const uint64_t iaHash = hash(state.inputAssembly);
128    const uint64_t rsHash = hash(state.rasterizationState);
129    const uint64_t dsHash = hash(state.depthStencilState);
130    const uint64_t cbsHash = hash(state.colorBlendState);
131    uint64_t finalHash = (iaHash << HASH_IA_SHIFT) | (rsHash << HASH_RS_SHIFT) | (dsHash << HASH_DS_SHIFT);
132    HashCombine(finalHash, cbsHash);
133    return finalHash;
134}
135
136RENDER_BEGIN_NAMESPACE()
137namespace {
138constexpr inline bool IsUniformBuffer(const DescriptorType descriptorType)
139{
140    return ((descriptorType == CORE_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) ||
141            (descriptorType == CORE_DESCRIPTOR_TYPE_UNIFORM_BUFFER));
142}
143constexpr inline bool IsStorageBuffer(const DescriptorType descriptorType)
144{
145    return ((descriptorType == CORE_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) ||
146            (descriptorType == CORE_DESCRIPTOR_TYPE_STORAGE_BUFFER));
147}
148
149ShaderManager::CompatibilityFlags GetPipelineLayoutCompatibilityFlags(
150    const PipelineLayout& lhs, const PipelineLayout& rhs)
151{
152    ShaderManager::CompatibilityFlags flags = ShaderManager::CompatibilityFlagBits::COMPATIBLE_BIT;
153    for (uint32_t setIdx = 0; setIdx < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT; ++setIdx) {
154        const auto& lSet = lhs.descriptorSetLayouts[setIdx];
155        const auto& rSet = rhs.descriptorSetLayouts[setIdx];
156        if (lSet.set == rSet.set) {
157            for (uint32_t lIdx = 0; lIdx < lSet.bindings.size(); ++lIdx) {
158                const auto& lBind = lSet.bindings[lIdx];
159                for (uint32_t rIdx = 0; rIdx < rSet.bindings.size(); ++rIdx) {
160                    const auto& rBind = rSet.bindings[rIdx];
161                    if (lBind.binding == rBind.binding) {
162                        if ((lBind.descriptorCount != rBind.descriptorCount) ||
163                            (lBind.descriptorType != rBind.descriptorType)) {
164                            // re-check dynamic offsets
165                            if ((IsUniformBuffer(lBind.descriptorType) != IsUniformBuffer(rBind.descriptorType)) &&
166                                (IsStorageBuffer(lBind.descriptorType) != IsStorageBuffer(rBind.descriptorType))) {
167                                flags = 0;
168                            }
169                        }
170                    }
171                }
172            }
173        }
174    }
175    if (flags != 0) {
176        // check for exact match
177        bool isExact = true;
178        for (uint32_t setIdx = 0; setIdx < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT; ++setIdx) {
179            const auto& lSet = lhs.descriptorSetLayouts[setIdx];
180            const auto& rSet = rhs.descriptorSetLayouts[setIdx];
181            if (lSet.set == rSet.set) {
182                if (lSet.bindings.size() == rSet.bindings.size()) {
183                    for (size_t idx = 0; idx < lSet.bindings.size(); ++idx) {
184                        const int cmpRes =
185                            std::memcmp(&(lSet.bindings[idx]), &(rSet.bindings[idx]), sizeof(lSet.bindings[idx]));
186                        if (cmpRes != 0) {
187                            isExact = false;
188                            break;
189                        }
190                    }
191                } else {
192                    isExact = false;
193                    break;
194                }
195            }
196        }
197        if (isExact) {
198            flags |= ShaderManager::CompatibilityFlagBits::EXACT_BIT;
199        }
200    }
201    return flags;
202}
203
204// NOTE: checking the type for validity is enough
205inline bool IsComputeShaderFunc(RenderHandle handle)
206{
207    return RenderHandleType::COMPUTE_SHADER_STATE_OBJECT == RenderHandleUtil::GetHandleType(handle);
208}
209
210inline bool IsShaderFunc(RenderHandle handle)
211{
212    return RenderHandleType::SHADER_STATE_OBJECT == RenderHandleUtil::GetHandleType(handle);
213}
214
215inline bool IsAnyShaderFunc(RenderHandle handle)
216{
217    return (RenderHandleType::COMPUTE_SHADER_STATE_OBJECT == RenderHandleUtil::GetHandleType(handle)) ||
218           (RenderHandleType::SHADER_STATE_OBJECT == RenderHandleUtil::GetHandleType(handle));
219}
220
221inline void GetShadersBySlot(
222    const uint32_t renderSlotId, const ShaderManager::ComputeMappings& mappings, vector<RenderHandleReference>& shaders)
223{
224    for (const auto& ref : mappings.clientData) {
225        if (ref.renderSlotId == renderSlotId) {
226            shaders.push_back(ref.rhr);
227        }
228    }
229}
230
231inline void GetShadersBySlot(const uint32_t renderSlotId, const ShaderManager::GraphicsMappings& mappings,
232    vector<RenderHandleReference>& shaders)
233{
234    for (const auto& ref : mappings.clientData) {
235        if (ref.renderSlotId == renderSlotId) {
236            shaders.push_back(ref.rhr);
237        }
238    }
239}
240
241inline void GetShadersBySlot(
242    const uint32_t renderSlotId, const ShaderManager::ComputeMappings& mappings, vector<RenderHandle>& shaders)
243{
244    for (const auto& ref : mappings.clientData) {
245        if (ref.renderSlotId == renderSlotId) {
246            shaders.push_back(ref.rhr.GetHandle());
247        }
248    }
249}
250
251inline void GetShadersBySlot(
252    const uint32_t renderSlotId, const ShaderManager::GraphicsMappings& mappings, vector<RenderHandle>& shaders)
253{
254    for (const auto& ref : mappings.clientData) {
255        if (ref.renderSlotId == renderSlotId) {
256            shaders.push_back(ref.rhr.GetHandle());
257        }
258    }
259}
260
261inline void GetGraphicsStatesBySlot(
262    const uint32_t renderSlotId, const ShaderManager::GraphicsStateData& gsd, vector<RenderHandleReference>& states)
263{
264    PLUGIN_ASSERT(gsd.data.size() == gsd.rhr.size());
265    for (size_t idx = 0; idx < gsd.data.size(); ++idx) {
266        const auto& ref = gsd.data[idx];
267        if (ref.renderSlotId == renderSlotId) {
268            states.push_back(gsd.rhr[idx]);
269        }
270    }
271}
272
273inline void GetGraphicsStatesBySlot(
274    const uint32_t renderSlotId, const ShaderManager::GraphicsStateData& gsd, vector<RenderHandle>& states)
275{
276    PLUGIN_ASSERT(gsd.data.size() == gsd.rhr.size());
277    for (size_t idx = 0; idx < gsd.data.size(); ++idx) {
278        const auto& ref = gsd.data[idx];
279        if (ref.renderSlotId == renderSlotId) {
280            states.push_back(gsd.rhr[idx].GetHandle());
281        }
282    }
283}
284
285inline RenderHandle GetHandle(const string_view path, const unordered_map<string, RenderHandle>& nameToClientHandle)
286{
287    if (auto const pos = nameToClientHandle.find(path); pos != nameToClientHandle.end()) {
288        return pos->second;
289    }
290    return {};
291}
292
293constexpr inline uint64_t HashHandleAndSlot(const RenderHandle& handle, const uint32_t renderSlotId)
294{
295    // normally there are < 16 render slot ids used which way less than 0xffff
296    // NOTE: the render slot id might be an invalid index
297    return (handle.id << 16ull) | (renderSlotId & 0xffff);
298}
299
300uint32_t GetBaseGraphicsStateVariantIndex(
301    const ShaderManager::GraphicsStateData& graphicsStates, const ShaderManager::GraphicsStateVariantCreateInfo& vci)
302{
303    uint32_t baseVariantIndex = INVALID_SM_INDEX;
304    if (!vci.baseShaderState.empty()) {
305        const string fullBaseName = vci.baseShaderState + vci.baseVariant;
306        if (const auto bhIter = graphicsStates.nameToIndex.find(fullBaseName);
307            bhIter != graphicsStates.nameToIndex.cend()) {
308            PLUGIN_ASSERT(bhIter->second < graphicsStates.rhr.size());
309            if ((bhIter->second < graphicsStates.rhr.size()) && graphicsStates.rhr[bhIter->second]) {
310                const RenderHandle baseHandle = graphicsStates.rhr[bhIter->second].GetHandle();
311                baseVariantIndex = RenderHandleUtil::GetIndexPart(baseHandle);
312            }
313        } else {
314            PLUGIN_LOG_W("base state not found (%s %s)", vci.baseShaderState.data(), vci.baseVariant.data());
315        }
316    }
317    return baseVariantIndex;
318}
319} // namespace
320
321ShaderManager::ShaderManager(Device& device) : device_(device) {}
322
323ShaderManager::~ShaderManager() = default;
324
325RenderHandleReference ShaderManager::Get(const RenderHandle& handle) const
326{
327    if (RenderHandleUtil::IsValid(handle)) {
328        const RenderHandleType handleType = RenderHandleUtil::GetHandleType(handle);
329        const uint32_t arrayIndex = RenderHandleUtil::GetIndexPart(handle);
330        if (handleType == RenderHandleType::COMPUTE_SHADER_STATE_OBJECT) {
331            if (arrayIndex < computeShaderMappings_.clientData.size()) {
332                return computeShaderMappings_.clientData[arrayIndex].rhr;
333            }
334        } else if (handleType == RenderHandleType::SHADER_STATE_OBJECT) {
335            if (arrayIndex < shaderMappings_.clientData.size()) {
336                return shaderMappings_.clientData[arrayIndex].rhr;
337            }
338        } else if (handleType == RenderHandleType::GRAPHICS_STATE) {
339            if (arrayIndex < graphicsStates_.rhr.size()) {
340                return graphicsStates_.rhr[arrayIndex];
341            }
342        } else if (handleType == RenderHandleType::PIPELINE_LAYOUT) {
343            if (arrayIndex < pl_.rhr.size()) {
344                return pl_.rhr[arrayIndex];
345            }
346        }
347        PLUGIN_LOG_I("invalid render handle (id: %" PRIu64 ", type: %u)", handle.id, static_cast<uint32_t>(handleType));
348    }
349    return RenderHandleReference {};
350}
351
352uint64_t ShaderManager::HashGraphicsState(const GraphicsState& graphicsState) const
353{
354    return BASE_NS::hash(graphicsState);
355}
356
357uint32_t ShaderManager::CreateRenderSlotId(const string_view renderSlot)
358{
359    if (renderSlot.empty()) {
360        return INVALID_SM_INDEX;
361    }
362
363    if (const auto iter = renderSlotIds_.nameToId.find(renderSlot); iter != renderSlotIds_.nameToId.cend()) {
364        return iter->second;
365    } else { // create new id
366        const uint32_t renderSlotId = static_cast<uint32_t>(renderSlotIds_.data.size());
367        renderSlotIds_.nameToId[renderSlot] = renderSlotId;
368        renderSlotIds_.data.push_back(RenderSlotData { renderSlotId, {}, {} });
369        return renderSlotId;
370    }
371}
372
373string ShaderManager::GetRenderSlotName(const uint32_t renderSlotId) const
374{
375    if (renderSlotId != INVALID_SM_INDEX) {
376        for (const auto& ref : renderSlotIds_.nameToId) {
377            if (ref.second == renderSlotId) {
378                return ref.first;
379            }
380        }
381    }
382    return {};
383}
384
385string ShaderManager::GetCategoryName(const uint32_t categoryId) const
386{
387    if (categoryId != INVALID_SM_INDEX) {
388        for (const auto& ref : category_.nameToId) {
389            if (ref.second == categoryId) {
390                return ref.first;
391            }
392        }
393    }
394    return {};
395}
396
397void ShaderManager::SetRenderSlotData(
398    const uint32_t renderSlotId, const RenderHandleReference& shaderHandle, const RenderHandleReference& stateHandle)
399{
400    if (renderSlotId < static_cast<uint32_t>(renderSlotIds_.data.size())) {
401#if (RENDER_VALIDATION_ENABLED == 1)
402        string renderSlotName = GetRenderSlotName(renderSlotId);
403#endif
404        if (IsAnyShaderFunc(shaderHandle.GetHandle())) {
405#if (RENDER_VALIDATION_ENABLED == 1)
406            if (renderSlotIds_.data[renderSlotId].shader) {
407                renderSlotName = GetRenderSlotName(renderSlotId);
408                PLUGIN_LOG_W(
409                    "RENDER_VALIDATION: Overwriting default shader for render slot (%s)", renderSlotName.c_str());
410            }
411#endif
412            renderSlotIds_.data[renderSlotId].shader = shaderHandle;
413        }
414        if (RenderHandleUtil::GetHandleType(stateHandle.GetHandle()) == RenderHandleType::GRAPHICS_STATE) {
415#if (RENDER_VALIDATION_ENABLED == 1)
416            if (renderSlotIds_.data[renderSlotId].graphicsState) {
417                renderSlotName = renderSlotName.empty() ? GetRenderSlotName(renderSlotId) : renderSlotName;
418                PLUGIN_LOG_W(
419                    "RENDER_VALIDATION: Overwriting default shader for render slot (%s)", renderSlotName.c_str());
420            }
421#endif
422            renderSlotIds_.data[renderSlotId].graphicsState = stateHandle;
423        }
424    }
425}
426
427uint32_t ShaderManager::CreateCategoryId(const string_view name)
428{
429    if (name.empty()) {
430        return INVALID_SM_INDEX;
431    }
432
433    if (const auto iter = category_.nameToId.find(name); iter != category_.nameToId.cend()) {
434        return iter->second;
435    } else { // create new id
436        const uint32_t id = static_cast<uint32_t>(category_.data.size());
437        category_.nameToId[name] = id;
438        category_.data.push_back(string(name));
439        return id;
440    }
441}
442
443RenderHandle ShaderManager::CreateClientData(
444    const string_view path, const RenderHandleType type, const ClientDataIndices& cdi)
445{
446    PLUGIN_ASSERT(computeShaderMappings_.clientData.size() == computeShaderMappings_.nameData.size());
447    PLUGIN_ASSERT(shaderMappings_.clientData.size() == shaderMappings_.nameData.size());
448
449    RenderHandle clientHandle;
450    PLUGIN_ASSERT(
451        (type == RenderHandleType::COMPUTE_SHADER_STATE_OBJECT) || (type == RenderHandleType::SHADER_STATE_OBJECT));
452    const uint64_t frameIndex = device_.GetFrameCount();
453    if (auto iter = nameToClientHandle_.find(path); iter != nameToClientHandle_.end()) {
454        clientHandle = iter->second;
455        // we update the frame index if the shader has been (re)loaded
456        const uint32_t arrayIndex = RenderHandleUtil::GetIndexPart(clientHandle);
457        if ((type == RenderHandleType::COMPUTE_SHADER_STATE_OBJECT) &&
458            (arrayIndex < static_cast<uint32_t>(computeShaderMappings_.clientData.size()))) {
459            computeShaderMappings_.clientData[arrayIndex].frameIndex = frameIndex;
460        } else if (arrayIndex < static_cast<uint32_t>(shaderMappings_.clientData.size())) {
461            shaderMappings_.clientData[arrayIndex].frameIndex = frameIndex;
462        }
463    } else {
464        const uint32_t arrayIndex = (type == RenderHandleType::COMPUTE_SHADER_STATE_OBJECT)
465                                        ? static_cast<uint32_t>(computeShaderMappings_.clientData.size())
466                                        : static_cast<uint32_t>(shaderMappings_.clientData.size());
467        clientHandle = RenderHandleUtil::CreateGpuResourceHandle(type, 0, arrayIndex, 0);
468        RenderHandleReference rhr =
469            RenderHandleReference(clientHandle, IRenderReferenceCounter::Ptr(new ShaderReferenceCounter()));
470        if (type == RenderHandleType::COMPUTE_SHADER_STATE_OBJECT) {
471            computeShaderMappings_.clientData.push_back({ move(rhr), {}, cdi.renderSlotIndex, cdi.pipelineLayoutIndex,
472                cdi.reflectionPipelineLayoutIndex, cdi.categoryIndex, frameIndex });
473            computeShaderMappings_.nameData.push_back({});
474        } else {
475            shaderMappings_.clientData.push_back({ move(rhr), {}, cdi.renderSlotIndex, cdi.pipelineLayoutIndex,
476                cdi.reflectionPipelineLayoutIndex, INVALID_SM_INDEX, INVALID_SM_INDEX, cdi.categoryIndex, frameIndex });
477            shaderMappings_.nameData.push_back({});
478        }
479        if (!path.empty()) {
480            nameToClientHandle_[path] = clientHandle;
481        }
482    }
483
484    return clientHandle;
485}
486
487RenderHandleReference ShaderManager::Create(
488    const ComputeShaderCreateData& createInfo, const ShaderPathCreateData& pathCreateInfo)
489{
490    PLUGIN_ASSERT(computeShaderMappings_.clientData.size() == computeShaderMappings_.nameData.size());
491
492    const string fullName = createInfo.path + pathCreateInfo.variantName;
493    // reflection pipeline layout
494    uint32_t reflectionPlIndex = INVALID_SM_INDEX;
495    if (const ShaderModule* cs = GetShaderModule(createInfo.shaderModuleIndex); cs) {
496        const RenderHandleReference plRhr = CreatePipelineLayout({ fullName, cs->GetPipelineLayout() });
497        reflectionPlIndex = RenderHandleUtil::GetIndexPart(plRhr.GetHandle());
498    }
499
500    auto const clientHandle = CreateClientData(fullName, RenderHandleType::COMPUTE_SHADER_STATE_OBJECT,
501        { createInfo.renderSlotId, createInfo.pipelineLayoutIndex, reflectionPlIndex, createInfo.categoryId });
502    if (createInfo.pipelineLayoutIndex != INVALID_SM_INDEX) {
503        pl_.computeShaderToIndex[clientHandle] = createInfo.pipelineLayoutIndex;
504    }
505
506    {
507        const auto lock = std::lock_guard(pendingMutex_);
508        pendingAllocations_.computeShaders.push_back(
509            { clientHandle, createInfo.shaderModuleIndex, createInfo.pipelineLayoutIndex });
510    }
511    if ((!createInfo.shaderFileStr.empty()) && RenderHandleUtil::IsValid(clientHandle)) {
512        // update shader file always
513        handleToShaderDataFile_.insert_or_assign(clientHandle, string(createInfo.shaderFileStr));
514    }
515    if (!createInfo.materialMetadata.empty()) {
516        MaterialMetadata metadata { string(createInfo.materialMetadata), json::value {} };
517        if (metadata.json = json::parse(metadata.raw.data()); metadata.json) {
518            // update metadata always
519            shaderToMetadata_.insert_or_assign(clientHandle, move(metadata));
520        }
521    }
522
523    const uint32_t index = RenderHandleUtil::GetIndexPart(clientHandle);
524    if (IsComputeShaderFunc(clientHandle) &&
525        (index < static_cast<uint32_t>(computeShaderMappings_.clientData.size()))) {
526        auto& nameDataRef = computeShaderMappings_.nameData[index];
527        nameDataRef.path = createInfo.path;
528        nameDataRef.variantName = pathCreateInfo.variantName;
529        nameDataRef.displayName = pathCreateInfo.displayName;
530        auto& clientDataRef = computeShaderMappings_.clientData[index];
531        // add base shader if given
532        if (!pathCreateInfo.baseShaderPath.empty()) {
533            if (const auto baseHandleIter = nameToClientHandle_.find(pathCreateInfo.baseShaderPath);
534                baseHandleIter != nameToClientHandle_.cend()) {
535                if (RenderHandleUtil::IsValid(baseHandleIter->second)) {
536                    clientDataRef.baseShaderHandle = baseHandleIter->second;
537                    const uint64_t hash = HashHandleAndSlot(clientDataRef.baseShaderHandle, createInfo.renderSlotId);
538                    hashToShaderVariant_[hash] = clientHandle;
539                }
540            } else {
541                PLUGIN_LOG_W("base shader (%s) not found for (%s)", pathCreateInfo.baseShaderPath.data(),
542                    createInfo.path.data());
543            }
544        }
545        return clientDataRef.rhr;
546    } else {
547        return {};
548    }
549}
550
551RenderHandleReference ShaderManager::Create(
552    const ShaderCreateData& createInfo, const ShaderPathCreateData& pathCreateInfo)
553{
554    PLUGIN_ASSERT(shaderMappings_.clientData.size() == shaderMappings_.nameData.size());
555
556    const string fullName = createInfo.path + pathCreateInfo.variantName;
557    // reflection pipeline layout
558    uint32_t reflectionPlIndex = INVALID_SM_INDEX;
559    {
560        const ShaderModule* vs = GetShaderModule(createInfo.vertShaderModuleIndex);
561        const ShaderModule* fs = GetShaderModule(createInfo.fragShaderModuleIndex);
562        if (vs && fs) {
563            const PipelineLayout layouts[] { vs->GetPipelineLayout(), fs->GetPipelineLayout() };
564            PipelineLayout pl;
565            GpuProgramUtil::CombinePipelineLayouts({ layouts, 2u }, pl);
566            const RenderHandleReference plRhr = CreatePipelineLayout({ fullName, pl });
567            reflectionPlIndex = RenderHandleUtil::GetIndexPart(plRhr.GetHandle());
568        }
569    }
570
571    auto const clientHandle = CreateClientData(fullName, RenderHandleType::SHADER_STATE_OBJECT,
572        { createInfo.renderSlotId, createInfo.pipelineLayoutIndex, reflectionPlIndex, createInfo.categoryId });
573
574    if (createInfo.pipelineLayoutIndex != INVALID_SM_INDEX) {
575        pl_.shaderToIndex[clientHandle] = createInfo.pipelineLayoutIndex;
576    }
577    if (createInfo.vertexInputDeclarationIndex != INVALID_SM_INDEX) {
578        shaderVid_.shaderToIndex[clientHandle] = createInfo.vertexInputDeclarationIndex;
579    }
580
581    {
582        const auto lock = std::lock_guard(pendingMutex_);
583        pendingAllocations_.shaders.push_back({ clientHandle, createInfo.vertShaderModuleIndex,
584            createInfo.fragShaderModuleIndex, createInfo.pipelineLayoutIndex, createInfo.vertexInputDeclarationIndex });
585    }
586
587    if ((!createInfo.shaderFileStr.empty()) && RenderHandleUtil::IsValid(clientHandle)) {
588        // update shader file always
589        handleToShaderDataFile_.insert_or_assign(clientHandle, string(createInfo.shaderFileStr));
590    }
591    if (!createInfo.materialMetadata.empty()) {
592        MaterialMetadata metadata { string(createInfo.materialMetadata), json::value {} };
593        if (metadata.json = json::parse(metadata.raw.data()); metadata.json) {
594            // update metadata always
595            shaderToMetadata_.insert_or_assign(clientHandle, move(metadata));
596        } else {
597            shaderToMetadata_.erase(clientHandle);
598        }
599    } else {
600        shaderToMetadata_.erase(clientHandle);
601    }
602
603    const uint32_t index = RenderHandleUtil::GetIndexPart(clientHandle);
604    if (IsShaderFunc(clientHandle) && (index < static_cast<uint32_t>(shaderMappings_.clientData.size()))) {
605        auto& nameDataRef = shaderMappings_.nameData[index];
606        nameDataRef.path = createInfo.path;
607        nameDataRef.variantName = pathCreateInfo.variantName;
608        nameDataRef.displayName = pathCreateInfo.displayName;
609        auto& clientDataRef = shaderMappings_.clientData[index];
610        clientDataRef.graphicsStateIndex = createInfo.graphicsStateIndex;
611        clientDataRef.vertexInputDeclarationIndex = createInfo.vertexInputDeclarationIndex;
612        // add base shader if given
613#if (RENDER_VALIDATION_ENABLED == 1)
614        if ((!pathCreateInfo.variantName.empty()) && pathCreateInfo.baseShaderPath.empty()) {
615            PLUGIN_LOG_W("RENDER_VALIDATION: base shader path not give to variant (%s %s)", createInfo.path.data(),
616                pathCreateInfo.variantName.data());
617        }
618#endif
619        if (!pathCreateInfo.baseShaderPath.empty()) {
620            if (const auto baseHandleIter = nameToClientHandle_.find(pathCreateInfo.baseShaderPath);
621                baseHandleIter != nameToClientHandle_.cend()) {
622                if (RenderHandleUtil::IsValid(baseHandleIter->second)) {
623                    clientDataRef.baseShaderHandle = baseHandleIter->second;
624                    const uint64_t hash = HashHandleAndSlot(clientDataRef.baseShaderHandle, createInfo.renderSlotId);
625                    hashToShaderVariant_[hash] = clientHandle;
626                }
627            } else {
628                PLUGIN_LOG_W("base shader (%s) not found for (%s)", pathCreateInfo.baseShaderPath.data(),
629                    createInfo.path.data());
630            }
631        }
632        return clientDataRef.rhr;
633    } else {
634        return {};
635    }
636}
637
638void ShaderManager::AddAdditionalNameForHandle(const RenderHandleReference& handle, const string_view name)
639{
640    if (handle) {
641        const RenderHandle rawHandle = handle.GetHandle();
642        const RenderHandleType handleType = RenderHandleUtil::GetHandleType(rawHandle);
643        // add name only if name not used yet
644        if ((handleType == RenderHandleType::COMPUTE_SHADER_STATE_OBJECT) ||
645            (handleType == RenderHandleType::SHADER_STATE_OBJECT)) {
646            if (!nameToClientHandle_.contains(name)) {
647                nameToClientHandle_[name] = rawHandle;
648            } else {
649                PLUGIN_LOG_W("trying to add additional name (%s) for shader handle, but the name is already in use",
650                    name.data());
651            }
652        }
653    }
654}
655
656RenderHandleReference ShaderManager::CreateComputeShader(
657    const ComputeShaderCreateInfo& createInfo, const string_view baseShaderPath, const string_view variantName)
658{
659    if (createInfo.shaderPaths.size() >= 1u) {
660        if (const uint32_t moduleIdx = GetShaderModuleIndex(createInfo.shaderPaths[0].path);
661            moduleIdx != INVALID_SM_INDEX) {
662            return Create(ComputeShaderCreateData { createInfo.path, createInfo.renderSlotId, createInfo.categoryId,
663                              RenderHandleUtil::GetIndexPart(createInfo.pipelineLayout), moduleIdx, {}, {} },
664                { baseShaderPath, variantName, {} });
665        } else {
666            PLUGIN_LOG_E("ShaderManager: compute shader (%s) creation failed, compute shader path (%s) not found",
667                string(createInfo.path).c_str(), string(createInfo.shaderPaths[0].path).c_str());
668        }
669    } else {
670        PLUGIN_LOG_E("ShaderManager: compute shader (%s) creation failed, no shader module paths given",
671            string(createInfo.path).c_str());
672    }
673    return {};
674}
675
676RenderHandleReference ShaderManager::CreateComputeShader(const ComputeShaderCreateInfo& createInfo)
677{
678    return CreateComputeShader(createInfo, "", "");
679}
680
681RenderHandleReference ShaderManager::CreateShader(
682    const ShaderCreateInfo& createInfo, const string_view baseShaderPath, const string_view variantName)
683{
684    if (createInfo.shaderPaths.size() >= 2u) {
685        const uint32_t vertShaderModule = GetShaderModuleIndex(createInfo.shaderPaths[0u].path);
686        const uint32_t fragShaderModule = GetShaderModuleIndex(createInfo.shaderPaths[1u].path);
687        if ((vertShaderModule != INVALID_SM_INDEX) && (fragShaderModule != INVALID_SM_INDEX)) {
688            return Create(ShaderCreateData { createInfo.path, createInfo.renderSlotId, createInfo.categoryId,
689                              RenderHandleUtil::GetIndexPart(createInfo.vertexInputDeclaration),
690                              RenderHandleUtil::GetIndexPart(createInfo.pipelineLayout),
691                              RenderHandleUtil::GetIndexPart(createInfo.graphicsState), vertShaderModule,
692                              fragShaderModule, {}, {} },
693                { baseShaderPath, variantName, {} });
694        } else {
695            PLUGIN_LOG_E("ShaderManager: shader (%s) creation failed, shader path (vert:%s) (frag:%s) not found",
696                string(createInfo.path).c_str(), string(createInfo.shaderPaths[0u].path).c_str(),
697                string(createInfo.shaderPaths[1u].path).c_str());
698        }
699    } else {
700        PLUGIN_LOG_E("ShaderManager: shader (%s) creation failed, no shader module paths given",
701            string(createInfo.path).c_str());
702    }
703    return {};
704}
705
706RenderHandleReference ShaderManager::CreateShader(const ShaderCreateInfo& createInfo)
707{
708    return CreateShader(createInfo, "", "");
709}
710
711void ShaderManager::HandlePendingAllocations()
712{
713    pendingMutex_.lock();
714    decltype(pendingAllocations_) pendingAllocations = move(pendingAllocations_);
715    pendingMutex_.unlock();
716
717    for (const auto& handleRef : pendingAllocations.destroyHandles) {
718        const RenderHandleType handleType = RenderHandleUtil::GetHandleType(handleRef);
719        const uint32_t arrayIndex = RenderHandleUtil::GetIndexPart(handleRef);
720        if (handleType == RenderHandleType::COMPUTE_SHADER_STATE_OBJECT) {
721            if (arrayIndex < static_cast<uint32_t>(computeShaders_.size())) {
722                computeShaders_[arrayIndex] = {};
723            }
724        } else if (handleType == RenderHandleType::SHADER_STATE_OBJECT) {
725            if (arrayIndex < static_cast<uint32_t>(shaders_.size())) {
726                shaders_[arrayIndex] = {};
727            }
728        }
729    }
730    HandlePendingShaders(pendingAllocations);
731    HandlePendingModules(pendingAllocations);
732
733    const uint64_t frameCount = device_.GetFrameCount();
734    constexpr uint64_t additionalFrameCount { 2u };
735    const auto minAge = device_.GetCommandBufferingCount() + additionalFrameCount;
736    const auto ageLimit = (frameCount < minAge) ? 0 : (frameCount - minAge);
737    auto CompareForErase = [](const auto ageLimit, auto& vec) {
738        for (auto iter = vec.begin(); iter != vec.end();) {
739            if (iter->frameIndex < ageLimit) {
740                iter = vec.erase(iter);
741            } else {
742                ++iter;
743            }
744        }
745    };
746    CompareForErase(ageLimit, deferredDestructions_.shaderModules);
747    CompareForErase(ageLimit, deferredDestructions_.computePrograms);
748    CompareForErase(ageLimit, deferredDestructions_.shaderPrograms);
749
750    std::swap(reloadedShadersForBackend_, reloadedShaders_);
751    reloadedShaders_.clear();
752}
753
754void ShaderManager::HandlePendingShaders(Allocs& allocs)
755{
756    const uint64_t frameCount = device_.GetFrameCount();
757    for (const auto& ref : allocs.computeShaders) {
758        const uint32_t arrayIndex = RenderHandleUtil::GetIndexPart(ref.handle);
759        ShaderModule* shaderModule = GetShaderModule(ref.computeModuleIndex);
760        if (shaderModule) {
761            if (arrayIndex < static_cast<uint32_t>(computeShaders_.size())) {
762                // replace with new (push old for deferred destruction)
763                deferredDestructions_.computePrograms.push_back({ frameCount, move(computeShaders_[arrayIndex].gsp) });
764                computeShaders_[arrayIndex] = { device_.CreateGpuComputeProgram({ shaderModule }),
765                    ref.pipelineLayoutIndex, ref.computeModuleIndex };
766            } else {
767                // new gpu resource
768                computeShaders_.push_back({ device_.CreateGpuComputeProgram({ shaderModule }), ref.pipelineLayoutIndex,
769                    ref.computeModuleIndex });
770            }
771        }
772#if (RENDER_VALIDATION_ENABLED == 1)
773        if (!shaderModule) {
774            PLUGIN_LOG_E("RENDER_VALIDATION: Compute shader module with index:%u, not found", ref.computeModuleIndex);
775        }
776#endif
777    }
778    for (const auto& ref : allocs.shaders) {
779        uint32_t arrayIndex = RenderHandleUtil::GetIndexPart(ref.handle);
780        ShaderModule* vertShaderModule = GetShaderModule(ref.vertModuleIndex);
781        ShaderModule* fragShaderModule = GetShaderModule(ref.fragModuleIndex);
782        if (vertShaderModule && fragShaderModule) {
783            if ((arrayIndex < static_cast<uint32_t>(shaders_.size()))) {
784                // replace with new (push old for deferred destruction)
785                deferredDestructions_.shaderPrograms.push_back({ frameCount, move(shaders_[arrayIndex].gsp) });
786                shaders_[arrayIndex] = { device_.CreateGpuShaderProgram({ vertShaderModule, fragShaderModule }),
787                    ref.pipelineLayoutIndex, ref.vertexInputDeclIndex, ref.vertModuleIndex, ref.fragModuleIndex };
788            } else { // new gpu resource
789                shaders_.push_back({ device_.CreateGpuShaderProgram({ vertShaderModule, fragShaderModule }),
790                    ref.pipelineLayoutIndex, ref.vertexInputDeclIndex, ref.vertModuleIndex, ref.fragModuleIndex });
791            }
792        }
793#if (RENDER_VALIDATION_ENABLED == 1)
794        if ((!vertShaderModule) || (!fragShaderModule)) {
795            PLUGIN_LOG_E("RENDER_VALIDATION: Shader module with index: %u or %u, not found", ref.vertModuleIndex,
796                ref.fragModuleIndex);
797        }
798#endif
799    }
800}
801
802void ShaderManager::HandlePendingModules(Allocs& allocs)
803{
804    const uint64_t frameCount = device_.GetFrameCount();
805    for (const auto modIdx : allocs.recreatedComputeModuleIndices) {
806        for (auto& shaderRef : computeShaders_) {
807            if (modIdx == shaderRef.compModuleIndex) {
808                if (ShaderModule* compModule = GetShaderModule(shaderRef.compModuleIndex); compModule) {
809                    deferredDestructions_.computePrograms.push_back({ frameCount, move(shaderRef.gsp) });
810                    shaderRef.gsp = device_.CreateGpuComputeProgram({ compModule });
811                }
812            }
813        }
814    }
815    for (const auto modIdx : allocs.recreatedShaderModuleIndices) {
816        for (auto& shaderRef : shaders_) {
817            if ((modIdx == shaderRef.vertModuleIndex) || (modIdx == shaderRef.fragModuleIndex)) {
818                ShaderModule* vertModule = GetShaderModule(shaderRef.vertModuleIndex);
819                ShaderModule* fragModule = GetShaderModule(shaderRef.fragModuleIndex);
820                if (vertModule && fragModule) {
821                    deferredDestructions_.shaderPrograms.push_back({ frameCount, move(shaderRef.gsp) });
822                    shaderRef.gsp = device_.CreateGpuShaderProgram({ vertModule, fragModule });
823                }
824            }
825        }
826    }
827}
828
829RenderHandleReference ShaderManager::GetShaderHandle(const string_view path) const
830{
831    const RenderHandle handle = GetHandle(path, nameToClientHandle_);
832    const RenderHandleType handleType = RenderHandleUtil::GetHandleType(handle);
833    const uint32_t index = RenderHandleUtil::GetIndexPart(handle);
834    if ((handleType == RenderHandleType::COMPUTE_SHADER_STATE_OBJECT) &&
835        (index < static_cast<uint32_t>(computeShaderMappings_.clientData.size()))) {
836        return computeShaderMappings_.clientData[index].rhr;
837    } else if ((handleType == RenderHandleType::SHADER_STATE_OBJECT) &&
838               (index < static_cast<uint32_t>(shaderMappings_.clientData.size()))) {
839        return shaderMappings_.clientData[index].rhr;
840    } else {
841        PLUGIN_LOG_W("ShaderManager: invalid shader %s", path.data());
842        return {};
843    }
844}
845
846RenderHandleReference ShaderManager::GetShaderHandle(const string_view path, const string_view variantName) const
847{
848    const string fullName = path + variantName;
849    const RenderHandle handle = GetHandle(fullName, nameToClientHandle_);
850    const RenderHandleType handleType = RenderHandleUtil::GetHandleType(handle);
851    const uint32_t index = RenderHandleUtil::GetIndexPart(handle);
852    if ((handleType == RenderHandleType::COMPUTE_SHADER_STATE_OBJECT) &&
853        (index < static_cast<uint32_t>(computeShaderMappings_.clientData.size()))) {
854        return computeShaderMappings_.clientData[index].rhr;
855    } else if ((handleType == RenderHandleType::SHADER_STATE_OBJECT) &&
856               (index < static_cast<uint32_t>(shaderMappings_.clientData.size()))) {
857        return shaderMappings_.clientData[index].rhr;
858    } else {
859        PLUGIN_LOG_W("ShaderManager: invalid shader (%s) variant (%s)", path.data(), variantName.data());
860        return {};
861    }
862}
863
864RenderHandleReference ShaderManager::GetShaderHandle(const RenderHandle& handle, const uint32_t renderSlotId) const
865{
866    const RenderHandleType handleType = RenderHandleUtil::GetHandleType(handle);
867    if ((handleType != RenderHandleType::COMPUTE_SHADER_STATE_OBJECT) &&
868        (handleType != RenderHandleType::SHADER_STATE_OBJECT)) {
869        return {}; // early out
870    }
871
872    const uint32_t index = RenderHandleUtil::GetIndexPart(handle);
873    RenderHandle baseShaderHandle;
874    // check first for own validity and possible base shader handle
875    if ((handleType == RenderHandleType::COMPUTE_SHADER_STATE_OBJECT) &&
876        (index < static_cast<uint32_t>(computeShaderMappings_.clientData.size()))) {
877        const auto& ref = computeShaderMappings_.clientData[index];
878        if (ref.renderSlotId == renderSlotId) {
879            return ref.rhr;
880        }
881        baseShaderHandle = ref.baseShaderHandle;
882    } else if ((handleType == RenderHandleType::SHADER_STATE_OBJECT) &&
883               (index < static_cast<uint32_t>(shaderMappings_.clientData.size()))) {
884        const auto& ref = shaderMappings_.clientData[index];
885        if (ref.renderSlotId == renderSlotId) {
886            return ref.rhr;
887        }
888        baseShaderHandle = ref.baseShaderHandle;
889    }
890    // try to find a match through base shader variant
891    if (RenderHandleUtil::IsValid(baseShaderHandle)) {
892        const uint64_t hash = HashHandleAndSlot(baseShaderHandle, renderSlotId);
893        if (const auto iter = hashToShaderVariant_.find(hash); iter != hashToShaderVariant_.cend()) {
894            const RenderHandleType baseHandleType = RenderHandleUtil::GetHandleType(iter->second);
895            const uint32_t arrayIndex = RenderHandleUtil::GetIndexPart(iter->second);
896            if ((baseHandleType == RenderHandleType::COMPUTE_SHADER_STATE_OBJECT) &&
897                (arrayIndex < computeShaderMappings_.clientData.size())) {
898                PLUGIN_ASSERT(computeShaderMappings_.clientData[arrayIndex].renderSlotId == renderSlotId);
899                return computeShaderMappings_.clientData[arrayIndex].rhr;
900            } else if ((baseHandleType == RenderHandleType::SHADER_STATE_OBJECT) &&
901                       (arrayIndex < shaderMappings_.clientData.size())) {
902                PLUGIN_ASSERT(shaderMappings_.clientData[arrayIndex].renderSlotId == renderSlotId);
903                return shaderMappings_.clientData[arrayIndex].rhr;
904            }
905        }
906    }
907    return {};
908}
909
910RenderHandleReference ShaderManager::GetShaderHandle(
911    const RenderHandleReference& handle, const uint32_t renderSlotId) const
912{
913    return GetShaderHandle(handle.GetHandle(), renderSlotId);
914}
915
916vector<RenderHandleReference> ShaderManager::GetShaders(const uint32_t renderSlotId) const
917{
918    vector<RenderHandleReference> shaders;
919    GetShadersBySlot(renderSlotId, shaderMappings_, shaders);
920    GetShadersBySlot(renderSlotId, computeShaderMappings_, shaders);
921    return shaders;
922}
923
924vector<RenderHandle> ShaderManager::GetShaderRawHandles(const uint32_t renderSlotId) const
925{
926    vector<RenderHandle> shaders;
927    GetShadersBySlot(renderSlotId, shaderMappings_, shaders);
928    GetShadersBySlot(renderSlotId, computeShaderMappings_, shaders);
929    return shaders;
930}
931
932RenderHandleReference ShaderManager::CreateGraphicsState(
933    const GraphicsStateCreateInfo& createInfo, const GraphicsStateVariantCreateInfo& variantCreateInfo)
934{
935    PLUGIN_ASSERT(graphicsStates_.rhr.size() == graphicsStates_.graphicsStates.size());
936    const uint32_t renderSlotId = CreateRenderSlotId(variantCreateInfo.renderSlot);
937    // NOTE: No collisions expected if path is used
938    const string fullName = createInfo.path + variantCreateInfo.variant;
939    uint32_t arrayIndex = INVALID_SM_INDEX;
940    if (auto nameIter = graphicsStates_.nameToIndex.find(fullName); nameIter != graphicsStates_.nameToIndex.end()) {
941        arrayIndex = static_cast<uint32_t>(nameIter->second);
942    }
943
944    uint32_t baseVariantIndex = INVALID_SM_INDEX;
945    RenderHandleReference rhr;
946    if (arrayIndex < graphicsStates_.rhr.size()) {
947        rhr = graphicsStates_.rhr[arrayIndex];
948        graphicsStates_.graphicsStates[arrayIndex] = createInfo.graphicsState;
949        const uint64_t hash = HashGraphicsState(createInfo.graphicsState);
950        baseVariantIndex = GetBaseGraphicsStateVariantIndex(graphicsStates_, variantCreateInfo);
951        graphicsStates_.data[arrayIndex] = { hash, renderSlotId, baseVariantIndex, variantCreateInfo.stateFlags };
952        graphicsStates_.hashToIndex[hash] = arrayIndex;
953    } else { // new
954        arrayIndex = static_cast<uint32_t>(graphicsStates_.rhr.size());
955        // NOTE: these are only updated for new states
956        if (!fullName.empty()) {
957            graphicsStates_.nameToIndex[fullName] = arrayIndex;
958        }
959        const RenderHandle handle = RenderHandleUtil::CreateHandle(RenderHandleType::GRAPHICS_STATE, arrayIndex);
960        graphicsStates_.rhr.push_back(
961            RenderHandleReference(handle, IRenderReferenceCounter::Ptr(new ShaderReferenceCounter())));
962        rhr = graphicsStates_.rhr[arrayIndex];
963        graphicsStates_.graphicsStates.push_back(createInfo.graphicsState);
964        const uint64_t hash = HashGraphicsState(createInfo.graphicsState);
965        // ordering matters, this fetches from nameToIndex
966        baseVariantIndex = GetBaseGraphicsStateVariantIndex(graphicsStates_, variantCreateInfo);
967        graphicsStates_.data.push_back({ hash, renderSlotId, baseVariantIndex, variantCreateInfo.stateFlags });
968        graphicsStates_.hashToIndex[hash] = arrayIndex;
969    }
970    if (baseVariantIndex < graphicsStates_.rhr.size()) {
971        const uint64_t variantHash = HashHandleAndSlot(graphicsStates_.rhr[baseVariantIndex].GetHandle(), renderSlotId);
972        if (variantHash != INVALID_SM_INDEX) {
973#if (RENDER_VALIDATION_ENABLED == 1)
974            if (graphicsStates_.variantHashToIndex.contains(variantHash)) {
975                PLUGIN_LOG_W("RENDER_VALIDATION: overwriting variant hash with %s %s", createInfo.path.data(),
976                    variantCreateInfo.variant.data());
977            }
978#endif
979            graphicsStates_.variantHashToIndex[variantHash] = RenderHandleUtil::GetIndexPart(rhr.GetHandle());
980        }
981    }
982
983    return rhr;
984}
985
986RenderHandleReference ShaderManager::CreateGraphicsState(const GraphicsStateCreateInfo& createInfo)
987{
988    return CreateGraphicsState(createInfo, {});
989}
990
991RenderHandleReference ShaderManager::GetGraphicsStateHandle(const string_view path) const
992{
993    if (const auto iter = graphicsStates_.nameToIndex.find(path); iter != graphicsStates_.nameToIndex.cend()) {
994        PLUGIN_ASSERT(iter->second < graphicsStates_.rhr.size());
995        return graphicsStates_.rhr[iter->second];
996    } else {
997        PLUGIN_LOG_W("ShaderManager: named graphics state not found: %s", string(path).c_str());
998        return {};
999    }
1000}
1001
1002RenderHandleReference ShaderManager::GetGraphicsStateHandle(const string_view path, const string_view variantName) const
1003{
1004    // NOTE: does not call the base GetGraphicsStateHandle due to better error logging
1005    const string fullName = string(path + variantName);
1006    if (const auto iter = graphicsStates_.nameToIndex.find(fullName); iter != graphicsStates_.nameToIndex.cend()) {
1007        PLUGIN_ASSERT(iter->second < graphicsStates_.rhr.size());
1008        return graphicsStates_.rhr[iter->second];
1009    } else {
1010        PLUGIN_LOG_W(
1011            "ShaderManager: named graphics state not found (name: %s variant: %s)", path.data(), variantName.data());
1012        return {};
1013    }
1014}
1015
1016RenderHandleReference ShaderManager::GetGraphicsStateHandle(
1017    const RenderHandle& handle, const uint32_t renderSlotId) const
1018{
1019    if (RenderHandleUtil::GetHandleType(handle) == RenderHandleType::GRAPHICS_STATE) {
1020        const uint32_t arrayIndex = RenderHandleUtil::GetIndexPart(handle);
1021        if (arrayIndex < static_cast<uint32_t>(graphicsStates_.data.size())) {
1022            // check for own validity
1023            const auto& data = graphicsStates_.data[arrayIndex];
1024            if (renderSlotId == data.renderSlotId) {
1025                return graphicsStates_.rhr[arrayIndex];
1026            }
1027            // check for base variant for hashing
1028            if (data.baseVariantIndex < static_cast<uint32_t>(graphicsStates_.data.size())) {
1029                const RenderHandle baseHandle = graphicsStates_.rhr[data.baseVariantIndex].GetHandle();
1030                const uint64_t hash = HashHandleAndSlot(baseHandle, renderSlotId);
1031                if (const auto iter = graphicsStates_.variantHashToIndex.find(hash);
1032                    iter != graphicsStates_.variantHashToIndex.cend()) {
1033                    PLUGIN_ASSERT(iter->second < static_cast<uint32_t>(graphicsStates_.rhr.size()));
1034                    return graphicsStates_.rhr[iter->second];
1035                }
1036            }
1037        }
1038    }
1039    return {};
1040}
1041
1042RenderHandleReference ShaderManager::GetGraphicsStateHandle(
1043    const RenderHandleReference& handle, const uint32_t renderSlotId) const
1044{
1045    return GetGraphicsStateHandle(handle.GetHandle(), renderSlotId);
1046}
1047
1048RenderHandleReference ShaderManager::GetGraphicsStateHandleByHash(const uint64_t hash) const
1049{
1050    if (const auto iter = graphicsStates_.hashToIndex.find(hash); iter != graphicsStates_.hashToIndex.cend()) {
1051        PLUGIN_ASSERT(iter->second < graphicsStates_.rhr.size());
1052        return graphicsStates_.rhr[iter->second];
1053    } else {
1054        return {};
1055    }
1056}
1057
1058RenderHandleReference ShaderManager::GetGraphicsStateHandleByShaderHandle(const RenderHandle& handle) const
1059{
1060    if (RenderHandleUtil::GetHandleType(handle) == RenderHandleType::SHADER_STATE_OBJECT) {
1061        const uint32_t arrayIndex = RenderHandleUtil::GetIndexPart(handle);
1062        if (arrayIndex < static_cast<uint32_t>(shaderMappings_.clientData.size())) {
1063            const uint32_t gsIndex = shaderMappings_.clientData[arrayIndex].graphicsStateIndex;
1064            if (gsIndex < static_cast<uint32_t>(graphicsStates_.graphicsStates.size())) {
1065                return graphicsStates_.rhr[gsIndex];
1066            }
1067#if (RENDER_VALIDATION_ENABLED == 1)
1068            PLUGIN_ASSERT(gsIndex != INVALID_SM_INDEX); // not and optional index ATM
1069            PLUGIN_ASSERT(gsIndex < graphicsStates_.rhr.size());
1070#endif
1071        }
1072    }
1073    return {};
1074}
1075
1076RenderHandleReference ShaderManager::GetGraphicsStateHandleByShaderHandle(const RenderHandleReference& handle) const
1077{
1078    return GetGraphicsStateHandleByShaderHandle(handle.GetHandle());
1079}
1080
1081GraphicsState ShaderManager::GetGraphicsState(const RenderHandleReference& handle) const
1082{
1083    return GetGraphicsStateRef(handle);
1084}
1085
1086vector<RenderHandleReference> ShaderManager::GetGraphicsStates(const uint32_t renderSlotId) const
1087{
1088    vector<RenderHandleReference> gfxStates;
1089    GetGraphicsStatesBySlot(renderSlotId, graphicsStates_, gfxStates);
1090    return gfxStates;
1091}
1092
1093const GraphicsState& ShaderManager::GetGraphicsStateRef(const RenderHandle& handle) const
1094{
1095    const RenderHandleType type = RenderHandleUtil::GetHandleType(handle);
1096    const uint32_t arrayIndex = RenderHandleUtil::GetIndexPart(handle);
1097    if ((type == RenderHandleType::GRAPHICS_STATE) &&
1098        (arrayIndex < static_cast<uint32_t>(graphicsStates_.graphicsStates.size()))) {
1099        return graphicsStates_.graphicsStates[arrayIndex];
1100    } else {
1101#if (RENDER_VALIDATION_ENABLED == 1)
1102        if (RenderHandleUtil::IsValid(handle) && (type != RenderHandleType::GRAPHICS_STATE)) {
1103            PLUGIN_LOG_W("RENDER_VALIDATION: invalid handle type given to GetGraphicsState()");
1104        }
1105#endif
1106        return defaultGraphicsState_;
1107    }
1108}
1109
1110const GraphicsState& ShaderManager::GetGraphicsStateRef(const RenderHandleReference& handle) const
1111{
1112    return GetGraphicsStateRef(handle.GetHandle());
1113}
1114
1115uint32_t ShaderManager::GetRenderSlotId(const string_view renderSlot) const
1116{
1117    if (const auto iter = renderSlotIds_.nameToId.find(renderSlot); iter != renderSlotIds_.nameToId.cend()) {
1118        return iter->second;
1119    } else {
1120        return INVALID_SM_INDEX;
1121    }
1122}
1123
1124uint32_t ShaderManager::GetRenderSlotId(const RenderHandle& handle) const
1125{
1126    uint32_t id = ~0u;
1127    const RenderHandleType handleType = RenderHandleUtil::GetHandleType(handle);
1128    const uint32_t arrayIndex = RenderHandleUtil::GetIndexPart(handle);
1129    if (handleType == RenderHandleType::COMPUTE_SHADER_STATE_OBJECT) {
1130        if (arrayIndex < computeShaderMappings_.clientData.size()) {
1131            id = computeShaderMappings_.clientData[arrayIndex].renderSlotId;
1132        }
1133    } else if (handleType == RenderHandleType::SHADER_STATE_OBJECT) {
1134        if (arrayIndex < shaderMappings_.clientData.size()) {
1135            id = shaderMappings_.clientData[arrayIndex].renderSlotId;
1136        }
1137    } else if (handleType == RenderHandleType::GRAPHICS_STATE) {
1138        if (arrayIndex < graphicsStates_.data.size()) {
1139            id = graphicsStates_.data[arrayIndex].renderSlotId;
1140        }
1141    }
1142    return id;
1143}
1144
1145uint32_t ShaderManager::GetRenderSlotId(const RenderHandleReference& handle) const
1146{
1147    return GetRenderSlotId(handle.GetHandle());
1148}
1149
1150IShaderManager::RenderSlotData ShaderManager::GetRenderSlotData(const uint32_t renderSlotId) const
1151{
1152    if (renderSlotId < static_cast<uint32_t>(renderSlotIds_.data.size())) {
1153        return renderSlotIds_.data[renderSlotId];
1154    } else {
1155        return {};
1156    }
1157}
1158
1159RenderHandleReference ShaderManager::GetVertexInputDeclarationHandleByShaderHandle(const RenderHandle& handle) const
1160{
1161    if (RenderHandleUtil::GetHandleType(handle) == RenderHandleType::SHADER_STATE_OBJECT) {
1162        const uint32_t arrayIndex = RenderHandleUtil::GetIndexPart(handle);
1163        auto& mappings = shaderMappings_;
1164        if (arrayIndex < mappings.clientData.size()) {
1165            const uint32_t vidIndex = mappings.clientData[arrayIndex].vertexInputDeclarationIndex;
1166            if (vidIndex < shaderVid_.rhr.size()) {
1167                PLUGIN_ASSERT(vidIndex < shaderVid_.rhr.size());
1168                return shaderVid_.rhr[vidIndex];
1169            }
1170        }
1171    }
1172    return {};
1173}
1174
1175RenderHandleReference ShaderManager::GetVertexInputDeclarationHandleByShaderHandle(
1176    const RenderHandleReference& handle) const
1177{
1178    return GetVertexInputDeclarationHandleByShaderHandle(handle.GetHandle());
1179}
1180
1181RenderHandleReference ShaderManager::GetVertexInputDeclarationHandle(const string_view path) const
1182{
1183    if (const auto iter = shaderVid_.nameToIndex.find(path); iter != shaderVid_.nameToIndex.cend()) {
1184        PLUGIN_ASSERT(iter->second < shaderVid_.rhr.size());
1185        return shaderVid_.rhr[iter->second];
1186    } else {
1187        PLUGIN_LOG_W("ShaderManager: vertex input declaration not found: %s", path.data());
1188        return {};
1189    }
1190}
1191
1192VertexInputDeclarationView ShaderManager::GetVertexInputDeclarationView(const RenderHandle& handle) const
1193{
1194    const RenderHandleType type = RenderHandleUtil::GetHandleType(handle);
1195    const uint32_t index = RenderHandleUtil::GetIndexPart(handle);
1196    if ((type == RenderHandleType::VERTEX_INPUT_DECLARATION) &&
1197        (index < static_cast<uint32_t>(shaderVid_.data.size()))) {
1198        const auto& ref = shaderVid_.data[index];
1199        return {
1200            array_view<const VertexInputDeclaration::VertexInputBindingDescription>(
1201                ref.bindingDescriptions, ref.bindingDescriptionCount),
1202            array_view<const VertexInputDeclaration::VertexInputAttributeDescription>(
1203                ref.attributeDescriptions, ref.attributeDescriptionCount),
1204        };
1205    } else {
1206#if (RENDER_VALIDATION_ENABLED == 1)
1207        if (RenderHandleUtil::IsValid(handle) && (type != RenderHandleType::VERTEX_INPUT_DECLARATION)) {
1208            PLUGIN_LOG_W("RENDER_VALIDATION: invalid handle type given to GetVertexInputDeclarationView()");
1209        }
1210#endif
1211        return {};
1212    }
1213}
1214
1215VertexInputDeclarationView ShaderManager::GetVertexInputDeclarationView(const RenderHandleReference& handle) const
1216{
1217    return GetVertexInputDeclarationView(handle.GetHandle());
1218}
1219
1220RenderHandleReference ShaderManager::CreateVertexInputDeclaration(const VertexInputDeclarationCreateInfo& createInfo)
1221{
1222    uint32_t arrayIndex = INVALID_SM_INDEX;
1223    if (auto nameIter = shaderVid_.nameToIndex.find(createInfo.path); nameIter != shaderVid_.nameToIndex.end()) {
1224        PLUGIN_ASSERT(nameIter->second < shaderVid_.rhr.size());
1225        arrayIndex = static_cast<uint32_t>(nameIter->second);
1226    }
1227    if (arrayIndex < static_cast<uint32_t>(shaderVid_.data.size())) {
1228        // inside core validation due to being very low info for common users
1229#if (RENDER_VALIDATION_ENABLED == 1)
1230        PLUGIN_LOG_I("ShaderManager: re-creating vertex input declaration (name %s)", createInfo.path.data());
1231#endif
1232    } else { // new
1233        arrayIndex = static_cast<uint32_t>(shaderVid_.data.size());
1234        const RenderHandle handle =
1235            RenderHandleUtil::CreateHandle(RenderHandleType::VERTEX_INPUT_DECLARATION, arrayIndex);
1236        shaderVid_.rhr.push_back(
1237            RenderHandleReference(handle, IRenderReferenceCounter::Ptr(new ShaderReferenceCounter())));
1238        shaderVid_.data.push_back(VertexInputDeclarationData {});
1239        // NOTE: only updated for new
1240        if (!createInfo.path.empty()) {
1241            shaderVid_.nameToIndex[createInfo.path] = arrayIndex;
1242        }
1243    }
1244
1245    if (arrayIndex < static_cast<uint32_t>(shaderVid_.data.size())) {
1246        const VertexInputDeclarationView& vertexInputDeclarationView = createInfo.vertexInputDeclarationView;
1247        VertexInputDeclarationData& ref = shaderVid_.data[arrayIndex];
1248        ref.bindingDescriptionCount = (uint32_t)vertexInputDeclarationView.bindingDescriptions.size();
1249        ref.attributeDescriptionCount = (uint32_t)vertexInputDeclarationView.attributeDescriptions.size();
1250
1251        PLUGIN_ASSERT(ref.bindingDescriptionCount <= PipelineStateConstants::MAX_VERTEX_BUFFER_COUNT);
1252        PLUGIN_ASSERT(ref.attributeDescriptionCount <= PipelineStateConstants::MAX_VERTEX_BUFFER_COUNT);
1253
1254        for (uint32_t idx = 0; idx < ref.bindingDescriptionCount; ++idx) {
1255            ref.bindingDescriptions[idx] = vertexInputDeclarationView.bindingDescriptions[idx];
1256        }
1257        for (uint32_t idx = 0; idx < ref.attributeDescriptionCount; ++idx) {
1258            ref.attributeDescriptions[idx] = vertexInputDeclarationView.attributeDescriptions[idx];
1259        }
1260        return shaderVid_.rhr[arrayIndex];
1261    } else {
1262        return {};
1263    }
1264}
1265
1266RenderHandleReference ShaderManager::GetPipelineLayoutHandleByShaderHandle(const RenderHandle& handle) const
1267{
1268    const RenderHandleType type = RenderHandleUtil::GetHandleType(handle);
1269    const uint32_t arrayIndex = RenderHandleUtil::GetIndexPart(handle);
1270    if (type == RenderHandleType::SHADER_STATE_OBJECT) {
1271        auto& mappings = shaderMappings_;
1272        if (arrayIndex < mappings.clientData.size()) {
1273            const uint32_t plIndex = mappings.clientData[arrayIndex].pipelineLayoutIndex;
1274            if (plIndex < static_cast<uint32_t>(pl_.rhr.size())) {
1275                PLUGIN_ASSERT(plIndex < static_cast<uint32_t>(pl_.rhr.size()));
1276                return pl_.rhr[plIndex];
1277            }
1278        }
1279    } else if (type == RenderHandleType::COMPUTE_SHADER_STATE_OBJECT) {
1280        auto& mappings = computeShaderMappings_;
1281        if (arrayIndex < mappings.clientData.size()) {
1282            const uint32_t plIndex = mappings.clientData[arrayIndex].pipelineLayoutIndex;
1283            if (plIndex < static_cast<uint32_t>(pl_.rhr.size())) {
1284                PLUGIN_ASSERT(plIndex < static_cast<uint32_t>(pl_.rhr.size()));
1285                return pl_.rhr[plIndex];
1286            }
1287        }
1288    }
1289    return {};
1290}
1291
1292RenderHandleReference ShaderManager::GetPipelineLayoutHandleByShaderHandle(const RenderHandleReference& handle) const
1293{
1294    return GetPipelineLayoutHandleByShaderHandle(handle.GetHandle());
1295}
1296
1297RenderHandleReference ShaderManager::GetPipelineLayoutHandle(const string_view path) const
1298{
1299    if (const auto iter = pl_.nameToIndex.find(path); iter != pl_.nameToIndex.cend()) {
1300        const uint32_t index = iter->second;
1301        PLUGIN_ASSERT(index < static_cast<uint32_t>(pl_.rhr.size()));
1302        return pl_.rhr[index];
1303    } else {
1304        PLUGIN_LOG_W("ShaderManager: pipeline layout not found: %s", path.data());
1305        return {};
1306    }
1307}
1308
1309PipelineLayout ShaderManager::GetPipelineLayout(const RenderHandle& handle) const
1310{
1311    return GetPipelineLayoutRef(handle);
1312}
1313
1314PipelineLayout ShaderManager::GetPipelineLayout(const RenderHandleReference& handle) const
1315{
1316    return GetPipelineLayoutRef(handle.GetHandle());
1317}
1318
1319const PipelineLayout& ShaderManager::GetPipelineLayoutRef(const RenderHandle& handle) const
1320{
1321    const RenderHandleType type = RenderHandleUtil::GetHandleType(handle);
1322    const uint32_t index = RenderHandleUtil::GetIndexPart(handle);
1323    if ((type == RenderHandleType::PIPELINE_LAYOUT) && (index < static_cast<uint32_t>(pl_.data.size()))) {
1324        return pl_.data[index];
1325    } else {
1326#if (RENDER_VALIDATION_ENABLED == 1)
1327        if (RenderHandleUtil::IsValid(handle) && (type != RenderHandleType::PIPELINE_LAYOUT)) {
1328            PLUGIN_LOG_W("RENDER_VALIDATION: invalid handle type given to GetPipelineLayout()");
1329        }
1330#endif
1331        return defaultPipelineLayout_;
1332    }
1333}
1334
1335RenderHandleReference ShaderManager::GetReflectionPipelineLayoutHandle(const RenderHandle& handle) const
1336{
1337    const RenderHandleType type = RenderHandleUtil::GetHandleType(handle);
1338    const uint32_t arrayIndex = RenderHandleUtil::GetIndexPart(handle);
1339    uint32_t plIndex = INVALID_SM_INDEX;
1340    if (type == RenderHandleType::SHADER_STATE_OBJECT) {
1341        if (arrayIndex < shaderMappings_.clientData.size()) {
1342            plIndex = shaderMappings_.clientData[arrayIndex].reflectionPipelineLayoutIndex;
1343        }
1344    } else if (type == RenderHandleType::COMPUTE_SHADER_STATE_OBJECT) {
1345        if (arrayIndex < computeShaderMappings_.clientData.size()) {
1346            plIndex = computeShaderMappings_.clientData[arrayIndex].reflectionPipelineLayoutIndex;
1347        }
1348    }
1349
1350    if (plIndex < pl_.data.size()) {
1351        return pl_.rhr[plIndex];
1352    } else {
1353#if (RENDER_VALIDATION_ENABLED == 1)
1354        PLUGIN_LOG_W("RENDER_VALIDATION: ShaderManager, invalid shader handle for GetReflectionPipelineLayoutHandle");
1355#endif
1356        return {};
1357    }
1358}
1359
1360RenderHandleReference ShaderManager::GetReflectionPipelineLayoutHandle(const RenderHandleReference& handle) const
1361{
1362    return GetReflectionPipelineLayoutHandle(handle.GetHandle());
1363}
1364
1365PipelineLayout ShaderManager::GetReflectionPipelineLayout(const RenderHandleReference& handle) const
1366{
1367    return GetReflectionPipelineLayoutRef(handle.GetHandle());
1368}
1369
1370const PipelineLayout& ShaderManager::GetReflectionPipelineLayoutRef(const RenderHandle& handle) const
1371{
1372    const RenderHandleType type = RenderHandleUtil::GetHandleType(handle);
1373    const uint32_t arrayIndex = RenderHandleUtil::GetIndexPart(handle);
1374    uint32_t plIndex = INVALID_SM_INDEX;
1375    if (type == RenderHandleType::SHADER_STATE_OBJECT) {
1376        if (arrayIndex < shaderMappings_.clientData.size()) {
1377            plIndex = shaderMappings_.clientData[arrayIndex].reflectionPipelineLayoutIndex;
1378        }
1379    } else if (type == RenderHandleType::COMPUTE_SHADER_STATE_OBJECT) {
1380        if (arrayIndex < computeShaderMappings_.clientData.size()) {
1381            plIndex = computeShaderMappings_.clientData[arrayIndex].reflectionPipelineLayoutIndex;
1382        }
1383    }
1384
1385    if (plIndex < pl_.data.size()) {
1386        return pl_.data[plIndex];
1387    } else {
1388#if (RENDER_VALIDATION_ENABLED == 1)
1389        PLUGIN_LOG_W("RENDER_VALIDATION: ShaderManager, invalid shader handle for GetReflectionPipelineLayout");
1390#endif
1391        return defaultPipelineLayout_;
1392    }
1393}
1394
1395ShaderSpecializationConstantView ShaderManager::GetReflectionSpecialization(const RenderHandle& handle) const
1396{
1397    const RenderHandleType type = RenderHandleUtil::GetHandleType(handle);
1398    const uint32_t arrayIndex = RenderHandleUtil::GetIndexPart(handle);
1399    if (type == RenderHandleType::SHADER_STATE_OBJECT) {
1400        // NOTE: at the moment there might not be availability yet, will be FIXED
1401        if (arrayIndex < shaders_.size()) {
1402            if (shaders_[arrayIndex].gsp) {
1403                return shaders_[arrayIndex].gsp->GetReflection().shaderSpecializationConstantView;
1404            }
1405        }
1406    } else if (type == RenderHandleType::COMPUTE_SHADER_STATE_OBJECT) {
1407        // NOTE: at the moment there might not be availability yet, will be FIXED
1408        if (arrayIndex < computeShaders_.size()) {
1409            if (computeShaders_[arrayIndex].gsp) {
1410                return computeShaders_[arrayIndex].gsp->GetReflection().shaderSpecializationConstantView;
1411            }
1412        }
1413    }
1414#if (RENDER_VALIDATION_ENABLED == 1)
1415    PLUGIN_LOG_W("RENDER_VALIDATION: ShaderManager, invalid shader handle for GetReflectionSpecialization");
1416#endif
1417    return defaultSSCV_;
1418}
1419
1420ShaderSpecializationConstantView ShaderManager::GetReflectionSpecialization(const RenderHandleReference& handle) const
1421{
1422    return GetReflectionSpecialization(handle.GetHandle());
1423}
1424
1425VertexInputDeclarationView ShaderManager::GetReflectionVertexInputDeclaration(const RenderHandle& handle) const
1426{
1427    const RenderHandleType type = RenderHandleUtil::GetHandleType(handle);
1428    const uint32_t arrayIndex = RenderHandleUtil::GetIndexPart(handle);
1429    if (type == RenderHandleType::SHADER_STATE_OBJECT) {
1430        // NOTE: at the moment there might not be availability yet, will be FIXED
1431        if (arrayIndex < shaders_.size()) {
1432            if (shaders_[arrayIndex].gsp) {
1433                return shaders_[arrayIndex].gsp->GetReflection().vertexInputDeclarationView;
1434            }
1435        }
1436    }
1437#if (RENDER_VALIDATION_ENABLED == 1)
1438    PLUGIN_LOG_W("RENDER_VALIDATION: ShaderManager, invalid shader handle for GetReflectionVertexInputDeclaration");
1439#endif
1440    return defaultVIDV_;
1441}
1442
1443VertexInputDeclarationView ShaderManager::GetReflectionVertexInputDeclaration(const RenderHandleReference& handle) const
1444{
1445    return GetReflectionVertexInputDeclaration(handle.GetHandle());
1446}
1447
1448ShaderThreadGroup ShaderManager::GetReflectionThreadGroupSize(const RenderHandle& handle) const
1449{
1450    const RenderHandleType type = RenderHandleUtil::GetHandleType(handle);
1451    const uint32_t arrayIndex = RenderHandleUtil::GetIndexPart(handle);
1452    if (type == RenderHandleType::COMPUTE_SHADER_STATE_OBJECT) {
1453        // NOTE: at the moment there might not be availability yet, will be FIXED
1454        if (arrayIndex < computeShaders_.size()) {
1455            if (computeShaders_[arrayIndex].gsp) {
1456                const auto& refl = computeShaders_[arrayIndex].gsp->GetReflection();
1457                return { refl.threadGroupSizeX, refl.threadGroupSizeY, refl.threadGroupSizeZ };
1458            }
1459        }
1460    }
1461#if (RENDER_VALIDATION_ENABLED == 1)
1462    PLUGIN_LOG_W("RENDER_VALIDATION: ShaderManager, invalid shader handle for GetReflectionThreadGroupSize");
1463#endif
1464    return defaultSTG_;
1465}
1466
1467ShaderThreadGroup ShaderManager::GetReflectionThreadGroupSize(const RenderHandleReference& handle) const
1468{
1469    return GetReflectionThreadGroupSize(handle.GetHandle());
1470}
1471
1472RenderHandleReference ShaderManager::CreatePipelineLayout(const PipelineLayoutCreateInfo& createInfo)
1473{
1474    uint32_t arrayIndex = INVALID_SM_INDEX;
1475    if (auto nameIter = pl_.nameToIndex.find(createInfo.path); nameIter != pl_.nameToIndex.end()) {
1476        PLUGIN_ASSERT(nameIter->second < pl_.rhr.size());
1477        arrayIndex = static_cast<uint32_t>(nameIter->second);
1478    }
1479
1480    if (arrayIndex < static_cast<uint32_t>(pl_.data.size())) { // replace
1481        // inside core validation due to being very low info for common users
1482#if (RENDER_VALIDATION_ENABLED == 1)
1483        PLUGIN_LOG_I("ShaderManager: re-creating pipeline layout (name %s)", createInfo.path.data());
1484#endif
1485    } else { // new
1486        arrayIndex = static_cast<uint32_t>(pl_.data.size());
1487        pl_.data.push_back(PipelineLayout {});
1488        // NOTE: only updated for new (should check with re-creation)
1489        if (!createInfo.path.empty()) {
1490            pl_.nameToIndex[createInfo.path] = arrayIndex;
1491        }
1492        pl_.rhr.push_back(RenderHandleReference {});
1493    }
1494
1495    if (arrayIndex < static_cast<uint32_t>(pl_.data.size())) {
1496        const PipelineLayout& pipelineLayout = createInfo.pipelineLayout;
1497        PipelineLayout& ref = pl_.data[arrayIndex];
1498#if (RENDER_VALIDATION_ENABLED == 1)
1499        if (pipelineLayout.descriptorSetCount > PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT ||
1500            pipelineLayout.pushConstant.byteSize > PipelineLayoutConstants::MAX_PUSH_CONSTANT_BYTE_SIZE) {
1501            PLUGIN_LOG_W(
1502                "Invalid pipeline layout sizes clamped (name:%s). Set count %u <= %u, push constant size %u <= %u",
1503                createInfo.path.data(), ref.descriptorSetCount, PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT,
1504                pipelineLayout.pushConstant.byteSize, PipelineLayoutConstants::MAX_PUSH_CONSTANT_BYTE_SIZE);
1505        }
1506#endif
1507        ref.pushConstant = pipelineLayout.pushConstant;
1508        ref.descriptorSetCount =
1509            Math::min(PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT, pipelineLayout.descriptorSetCount);
1510        ref.pushConstant.byteSize =
1511            Math::min(PipelineLayoutConstants::MAX_PUSH_CONSTANT_BYTE_SIZE, pipelineLayout.pushConstant.byteSize);
1512        uint32_t descriptorSetBitmask = 0;
1513        // can be user generated pipeline layout (i.e. set index might be different than index)
1514        for (uint32_t idx = 0; idx < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT; ++idx) {
1515            const uint32_t setIdx = pipelineLayout.descriptorSetLayouts[idx].set;
1516            if (setIdx < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT) {
1517                ref.descriptorSetLayouts[setIdx] = pipelineLayout.descriptorSetLayouts[setIdx];
1518                descriptorSetBitmask |= (1 << setIdx);
1519            }
1520        }
1521
1522        const RenderHandle handle =
1523            RenderHandleUtil::CreateHandle(RenderHandleType::PIPELINE_LAYOUT, arrayIndex, 0, descriptorSetBitmask);
1524        pl_.rhr[arrayIndex] = RenderHandleReference(handle, IRenderReferenceCounter::Ptr(new ShaderReferenceCounter()));
1525        return pl_.rhr[arrayIndex];
1526    } else {
1527        return {};
1528    }
1529}
1530
1531const GpuComputeProgram* ShaderManager::GetGpuComputeProgram(const RenderHandle& handle) const
1532{
1533    if (!IsComputeShaderFunc(handle)) {
1534        PLUGIN_LOG_E("ShaderManager: invalid compute shader handle");
1535        return nullptr;
1536    }
1537    const uint32_t index = RenderHandleUtil::GetIndexPart(handle);
1538    if (index < static_cast<uint32_t>(computeShaders_.size())) {
1539        return computeShaders_[index].gsp.get();
1540    } else {
1541        PLUGIN_LOG_E("ShaderManager: invalid compute shader handle");
1542        return nullptr;
1543    }
1544}
1545
1546const GpuShaderProgram* ShaderManager::GetGpuShaderProgram(const RenderHandle& handle) const
1547{
1548    if (!IsShaderFunc(handle)) {
1549        PLUGIN_LOG_E("ShaderManager: invalid shader handle");
1550        return nullptr;
1551    }
1552    const uint32_t index = RenderHandleUtil::GetIndexPart(handle);
1553    if (index < static_cast<uint32_t>(shaders_.size())) {
1554        return shaders_[index].gsp.get();
1555    } else {
1556        PLUGIN_LOG_E("ShaderManager: invalid shader handle");
1557        return nullptr;
1558    }
1559}
1560
1561uint32_t ShaderManager::CreateShaderModule(const string_view path, const ShaderModuleCreateInfo& createInfo)
1562{
1563    auto& nameToIdx = shaderModules_.nameToIndex;
1564    auto& modules = shaderModules_.shaderModules;
1565    if (auto iter = nameToIdx.find(path); iter != nameToIdx.end()) {
1566        PLUGIN_ASSERT(iter->second < modules.size());
1567        // inside core validation due to being very low info for common users
1568#if (RENDER_VALIDATION_ENABLED == 1)
1569        PLUGIN_LOG_I("ShaderManager: re-creating shader module %s", path.data());
1570#endif
1571        // check that we don't push the same indices multiple times
1572        bool found = false;
1573        for (const auto& ref : pendingAllocations_.recreatedShaderModuleIndices) {
1574            if (ref == iter->second) {
1575                found = true;
1576                break;
1577            }
1578        }
1579        if (!found) {
1580            pendingAllocations_.recreatedShaderModuleIndices.push_back(iter->second);
1581        }
1582        deferredDestructions_.shaderModules.push_back({ device_.GetFrameCount(), move(modules[iter->second]) });
1583        modules[iter->second] = device_.CreateShaderModule(createInfo);
1584        return iter->second;
1585    } else {
1586        const uint32_t idx = static_cast<uint32_t>(modules.size());
1587        if (!path.empty()) {
1588            nameToIdx[path] = idx;
1589        }
1590        modules.push_back(device_.CreateShaderModule(createInfo));
1591        return idx;
1592    }
1593}
1594
1595ShaderModule* ShaderManager::GetShaderModule(const uint32_t index) const
1596{
1597    const auto& modules = shaderModules_.shaderModules;
1598    if (index < modules.size()) {
1599        return modules[index].get();
1600    } else {
1601        return nullptr;
1602    }
1603}
1604
1605uint32_t ShaderManager::GetShaderModuleIndex(const string_view path) const
1606{
1607    const auto& nameToIdx = shaderModules_.nameToIndex;
1608    if (const auto iter = nameToIdx.find(path); iter != nameToIdx.cend()) {
1609        PLUGIN_ASSERT(iter->second < shaderModules_.shaderModules.size());
1610        return iter->second;
1611    } else {
1612        return INVALID_SM_INDEX;
1613    }
1614}
1615
1616bool ShaderManager::IsComputeShader(const RenderHandleReference& handle) const
1617{
1618    return IsComputeShaderFunc(handle.GetHandle());
1619}
1620
1621bool ShaderManager::IsShader(const RenderHandleReference& handle) const
1622{
1623    return IsShaderFunc(handle.GetHandle());
1624}
1625
1626void ShaderManager::LoadShaderFiles(const ShaderFilePathDesc& desc)
1627{
1628    if (shaderLoader_) {
1629        shaderLoader_->Load(desc);
1630    }
1631}
1632
1633void ShaderManager::LoadShaderFile(const string_view uri)
1634{
1635    if (shaderLoader_ && (!uri.empty())) {
1636        shaderLoader_->LoadFile(uri, false);
1637    }
1638}
1639
1640void ShaderManager::UnloadShaderFiles(const ShaderFilePathDesc& desc) {}
1641
1642void ShaderManager::ReloadShaderFile(const string_view uri)
1643{
1644    if (shaderLoader_ && (!uri.empty())) {
1645        shaderLoader_->LoadFile(uri, true);
1646        if (const auto iter = nameToClientHandle_.find(uri); iter != nameToClientHandle_.cend()) {
1647            reloadedShaders_.push_back(iter->second);
1648        }
1649    }
1650}
1651
1652bool ShaderManager::HasReloadedShaderForBackend() const
1653{
1654    return !reloadedShadersForBackend_.empty();
1655}
1656
1657BASE_NS::array_view<const RenderHandle> ShaderManager::GetReloadedShadersForBackend() const
1658{
1659    return reloadedShadersForBackend_;
1660}
1661
1662const BASE_NS::string_view ShaderManager::GetShaderFile(const RenderHandleReference& handle) const
1663{
1664    if (const auto iter = handleToShaderDataFile_.find(handle.GetHandle()); iter != handleToShaderDataFile_.cend()) {
1665        return iter->second;
1666    }
1667    return {};
1668}
1669
1670const json::value* ShaderManager::GetMaterialMetadata(const RenderHandleReference& handle) const
1671{
1672    if (const auto iter = shaderToMetadata_.find(handle.GetHandle()); iter != shaderToMetadata_.end()) {
1673        return &iter->second.json;
1674    }
1675    return nullptr;
1676}
1677
1678void ShaderManager::DestroyShader(const RenderHandle handle)
1679{
1680    PLUGIN_ASSERT(computeShaderMappings_.clientData.size() == computeShaderMappings_.nameData.size());
1681    PLUGIN_ASSERT(shaderMappings_.clientData.size() == shaderMappings_.nameData.size());
1682
1683    auto eraseIndexData = [](auto& mapStore, const RenderHandle handle) {
1684        if (auto const pos = std::find_if(
1685            mapStore.begin(), mapStore.end(), [handle](auto const& element) { return element.second == handle; });
1686            pos != mapStore.end()) {
1687            mapStore.erase(pos);
1688        }
1689    };
1690
1691    const uint32_t index = RenderHandleUtil::GetIndexPart(handle);
1692    if (IsComputeShaderFunc(handle)) {
1693        auto& mappings = computeShaderMappings_;
1694        if (index < static_cast<uint32_t>(mappings.clientData.size())) {
1695            mappings.clientData[index] = {};
1696            mappings.nameData[index] = {};
1697            eraseIndexData(nameToClientHandle_, handle);
1698            {
1699                const auto lock = std::lock_guard(pendingMutex_);
1700                pendingAllocations_.destroyHandles.push_back(handle);
1701            }
1702        }
1703    } else if (IsShaderFunc(handle)) {
1704        auto& mappings = shaderMappings_;
1705        if (index < static_cast<uint32_t>(mappings.clientData.size())) {
1706            mappings.clientData[index] = {};
1707            mappings.nameData[index] = {};
1708            eraseIndexData(nameToClientHandle_, handle);
1709            {
1710                const auto lock = std::lock_guard(pendingMutex_);
1711                pendingAllocations_.destroyHandles.push_back(handle);
1712            }
1713        }
1714    }
1715}
1716
1717void ShaderManager::Destroy(const RenderHandleReference& handle)
1718{
1719    const RenderHandle rawHandle = handle.GetHandle();
1720    const RenderHandleType handleType = RenderHandleUtil::GetHandleType(rawHandle);
1721    if ((handleType == RenderHandleType::COMPUTE_SHADER_STATE_OBJECT) ||
1722        (handleType == RenderHandleType::SHADER_STATE_OBJECT)) {
1723        DestroyShader(rawHandle);
1724    } else if (handleType == RenderHandleType::GRAPHICS_STATE) {
1725        DestroyGraphicsState(rawHandle);
1726    } else if (handleType == RenderHandleType::PIPELINE_LAYOUT) {
1727        DestroyPipelineLayout(rawHandle);
1728    } else if (handleType == RenderHandleType::VERTEX_INPUT_DECLARATION) {
1729        DestroyVertexInputDeclaration(rawHandle);
1730    }
1731}
1732
1733void ShaderManager::DestroyGraphicsState(const RenderHandle handle)
1734{
1735    const uint32_t index = RenderHandleUtil::GetIndexPart(handle);
1736    if (index < static_cast<uint32_t>(graphicsStates_.rhr.size())) {
1737        graphicsStates_.rhr[index] = {};
1738        graphicsStates_.data[index] = {};
1739        graphicsStates_.graphicsStates[index] = {};
1740
1741        auto eraseIndexData = [](auto& mapStore, const uint32_t index) {
1742            if (auto const pos = std::find_if(
1743                mapStore.begin(), mapStore.end(), [index](auto const& element) { return element.second == index; });
1744                pos != mapStore.end()) {
1745                mapStore.erase(pos);
1746            }
1747        };
1748        eraseIndexData(graphicsStates_.nameToIndex, index);
1749        eraseIndexData(graphicsStates_.hashToIndex, index);
1750        // NOTE: shaderToStates needs to be added
1751    }
1752}
1753
1754void ShaderManager::DestroyPipelineLayout(const RenderHandle handle)
1755{
1756    const uint32_t index = RenderHandleUtil::GetIndexPart(handle);
1757    if (index < static_cast<uint32_t>(pl_.rhr.size())) {
1758        pl_.rhr[index] = {};
1759        pl_.data[index] = {};
1760
1761        auto eraseIndexData = [](auto& mapStore, const uint32_t index) {
1762            if (auto const pos = std::find_if(
1763                mapStore.begin(), mapStore.end(), [index](auto const& element) { return element.second == index; });
1764                pos != mapStore.end()) {
1765                mapStore.erase(pos);
1766            }
1767        };
1768        eraseIndexData(pl_.nameToIndex, index);
1769        eraseIndexData(pl_.computeShaderToIndex, index);
1770        eraseIndexData(pl_.shaderToIndex, index);
1771    }
1772}
1773
1774void ShaderManager::DestroyVertexInputDeclaration(const RenderHandle handle)
1775{
1776    const uint32_t index = RenderHandleUtil::GetIndexPart(handle);
1777    if (index < static_cast<uint32_t>(shaderVid_.rhr.size())) {
1778        shaderVid_.rhr[index] = {};
1779        shaderVid_.data[index] = {};
1780
1781        auto eraseIndexData = [](auto& mapStore, const uint32_t index) {
1782            if (auto const pos = std::find_if(
1783                mapStore.begin(), mapStore.end(), [index](auto const& element) { return element.second == index; });
1784                pos != mapStore.end()) {
1785                mapStore.erase(pos);
1786            }
1787        };
1788        eraseIndexData(shaderVid_.nameToIndex, index);
1789        eraseIndexData(shaderVid_.shaderToIndex, index);
1790    }
1791}
1792
1793vector<RenderHandleReference> ShaderManager::GetShaders(
1794    const RenderHandleReference& handle, const ShaderStageFlags shaderStageFlags) const
1795{
1796    vector<RenderHandleReference> shaders;
1797    if ((shaderStageFlags &
1798            (CORE_SHADER_STAGE_VERTEX_BIT | CORE_SHADER_STAGE_FRAGMENT_BIT | CORE_SHADER_STAGE_COMPUTE_BIT)) == 0) {
1799        return shaders;
1800    }
1801    const RenderHandleType handleType = handle.GetHandleType();
1802    const uint32_t handleIndex = RenderHandleUtil::GetIndexPart(handle.GetHandle());
1803    if (handleType == RenderHandleType::GRAPHICS_STATE) {
1804#if (RENDER_VALIDATION_ENABLED == 1)
1805        PLUGIN_LOG_W("RENDER_VALIDATION: GetShaders with graphics state handle not supported");
1806#endif
1807    } else if ((handleType == RenderHandleType::PIPELINE_LAYOUT) ||
1808               (handleType == RenderHandleType::VERTEX_INPUT_DECLARATION)) {
1809        if (shaderStageFlags & ShaderStageFlagBits::CORE_SHADER_STAGE_COMPUTE_BIT) {
1810            for (const auto& ref : computeShaderMappings_.clientData) {
1811                if (ref.pipelineLayoutIndex == handleIndex) {
1812                    shaders.push_back(ref.rhr);
1813                }
1814            }
1815        }
1816        if (shaderStageFlags & ShaderStageFlagBits::CORE_SHADER_STAGE_ALL_GRAPHICS) {
1817            for (const auto& ref : shaderMappings_.clientData) {
1818                if (ref.vertexInputDeclarationIndex == handleIndex) {
1819                    shaders.push_back(ref.rhr);
1820                }
1821            }
1822        }
1823    }
1824    return shaders;
1825}
1826
1827vector<RenderHandle> ShaderManager::GetShaders(
1828    const RenderHandle& handle, const ShaderStageFlags shaderStageFlags) const
1829{
1830    vector<RenderHandle> shaders;
1831    if ((shaderStageFlags &
1832            (CORE_SHADER_STAGE_VERTEX_BIT | CORE_SHADER_STAGE_FRAGMENT_BIT | CORE_SHADER_STAGE_COMPUTE_BIT)) == 0) {
1833        return shaders;
1834    }
1835    const RenderHandleType handleType = RenderHandleUtil::GetHandleType(handle);
1836    const uint32_t handleIndex = RenderHandleUtil::GetIndexPart(handle);
1837    if (handleType == RenderHandleType::GRAPHICS_STATE) {
1838#if (RENDER_VALIDATION_ENABLED == 1)
1839        PLUGIN_LOG_W("RENDER_VALIDATION: GetShaders with graphics state handle not supported");
1840#endif
1841    } else if ((handleType == RenderHandleType::PIPELINE_LAYOUT) ||
1842               (handleType == RenderHandleType::VERTEX_INPUT_DECLARATION)) {
1843        if (shaderStageFlags & ShaderStageFlagBits::CORE_SHADER_STAGE_COMPUTE_BIT) {
1844            for (const auto& ref : computeShaderMappings_.clientData) {
1845                if (ref.pipelineLayoutIndex == handleIndex) {
1846                    shaders.push_back(ref.rhr.GetHandle());
1847                }
1848            }
1849        }
1850        if (shaderStageFlags & ShaderStageFlagBits::CORE_SHADER_STAGE_ALL_GRAPHICS) {
1851            for (const auto& ref : shaderMappings_.clientData) {
1852                if (ref.vertexInputDeclarationIndex == handleIndex) {
1853                    shaders.push_back(ref.rhr.GetHandle());
1854                }
1855            }
1856        }
1857    }
1858    return shaders;
1859}
1860
1861vector<RenderHandleReference> ShaderManager::GetShaders() const
1862{
1863    vector<RenderHandleReference> shaders;
1864    shaders.reserve(computeShaderMappings_.clientData.size() + shaderMappings_.clientData.size());
1865    for (const auto& ref : computeShaderMappings_.clientData) {
1866        if (ref.rhr) {
1867            shaders.push_back(ref.rhr);
1868        }
1869    }
1870    for (const auto& ref : shaderMappings_.clientData) {
1871        if (ref.rhr) {
1872            shaders.push_back(ref.rhr);
1873        }
1874    }
1875    return shaders;
1876}
1877
1878vector<RenderHandleReference> ShaderManager::GetGraphicsStates() const
1879{
1880    vector<RenderHandleReference> states;
1881    states.reserve(graphicsStates_.rhr.size());
1882    for (const auto& ref : graphicsStates_.rhr) {
1883        if (ref) {
1884            states.push_back(ref);
1885        }
1886    }
1887    return states;
1888}
1889
1890vector<RenderHandleReference> ShaderManager::GetPipelineLayouts() const
1891{
1892    vector<RenderHandleReference> pls;
1893    pls.reserve(pl_.rhr.size());
1894    for (const auto& ref : pl_.rhr) {
1895        if (ref) {
1896            pls.push_back(ref);
1897        }
1898    }
1899    return pls;
1900}
1901
1902vector<RenderHandleReference> ShaderManager::GetVertexInputDeclarations() const
1903{
1904    vector<RenderHandleReference> vids;
1905    vids.reserve(shaderVid_.rhr.size());
1906    for (const auto& ref : shaderVid_.rhr) {
1907        if (ref) {
1908            vids.push_back(ref);
1909        }
1910    }
1911    return vids;
1912}
1913
1914IShaderManager::IdDesc ShaderManager::GetShaderIdDesc(const RenderHandle handle) const
1915{
1916    PLUGIN_ASSERT(computeShaderMappings_.clientData.size() == computeShaderMappings_.nameData.size());
1917    PLUGIN_ASSERT(shaderMappings_.clientData.size() == shaderMappings_.nameData.size());
1918    const RenderHandleType handleType = RenderHandleUtil::GetHandleType(handle);
1919    const uint32_t index = RenderHandleUtil::GetIndexPart(handle);
1920    IdDesc desc;
1921    if ((handleType == RenderHandleType::COMPUTE_SHADER_STATE_OBJECT) &&
1922        (index < static_cast<uint32_t>(computeShaderMappings_.clientData.size()))) {
1923        const auto& cdRef = computeShaderMappings_.clientData[index];
1924        const auto& nameRef = computeShaderMappings_.nameData[index];
1925        desc.frameIndex = cdRef.frameIndex;
1926        desc.renderSlot = GetRenderSlotName(cdRef.renderSlotId);
1927        desc.category = GetCategoryName(cdRef.categoryId);
1928        desc.displayName = nameRef.displayName;
1929        desc.path = nameRef.path;
1930        desc.variant = nameRef.variantName;
1931    } else if ((handleType == RenderHandleType::SHADER_STATE_OBJECT) &&
1932               (index < static_cast<uint32_t>(shaderMappings_.clientData.size()))) {
1933        const auto& cdRef = shaderMappings_.clientData[index];
1934        const auto& nameRef = shaderMappings_.nameData[index];
1935        desc.frameIndex = cdRef.frameIndex;
1936        desc.renderSlot = GetRenderSlotName(cdRef.renderSlotId);
1937        desc.category = GetCategoryName(cdRef.categoryId);
1938        desc.displayName = nameRef.displayName;
1939        desc.path = nameRef.path;
1940        desc.variant = nameRef.variantName;
1941    }
1942    return desc;
1943}
1944
1945uint64_t ShaderManager::GetShaderFrameIndex(const RenderHandle handle) const
1946{
1947    const RenderHandleType handleType = RenderHandleUtil::GetHandleType(handle);
1948    const uint32_t index = RenderHandleUtil::GetIndexPart(handle);
1949    uint64_t frameIndex = 0;
1950    if ((handleType == RenderHandleType::COMPUTE_SHADER_STATE_OBJECT) &&
1951        (index < static_cast<uint32_t>(computeShaderMappings_.clientData.size()))) {
1952        frameIndex = computeShaderMappings_.clientData[index].frameIndex;
1953    } else if ((handleType == RenderHandleType::SHADER_STATE_OBJECT) &&
1954               (index < static_cast<uint32_t>(shaderMappings_.clientData.size()))) {
1955        frameIndex = shaderMappings_.clientData[index].frameIndex;
1956    }
1957    return frameIndex;
1958}
1959
1960IShaderManager::IdDesc ShaderManager::GetIdDesc(const RenderHandleReference& handle) const
1961{
1962    auto GetIdDesc = [](const auto& nameToIndex, const auto handleIndex) {
1963        IdDesc desc;
1964        for (const auto& ref : nameToIndex) {
1965            if (ref.second == handleIndex) {
1966                desc.path = ref.first;
1967            }
1968        }
1969        return desc;
1970    };
1971    const RenderHandle rawHandle = handle.GetHandle();
1972    const RenderHandleType handleType = RenderHandleUtil::GetHandleType(rawHandle);
1973    const uint32_t handleIndex = RenderHandleUtil::GetIndexPart(rawHandle);
1974    IdDesc desc;
1975    if ((handleType == RenderHandleType::COMPUTE_SHADER_STATE_OBJECT) ||
1976        (handleType == RenderHandleType::SHADER_STATE_OBJECT)) {
1977        desc = GetShaderIdDesc(rawHandle);
1978    } else if ((handleType == RenderHandleType::GRAPHICS_STATE) && (handleIndex < graphicsStates_.rhr.size())) {
1979        desc = GetIdDesc(graphicsStates_.nameToIndex, handleIndex);
1980    } else if ((handleType == RenderHandleType::PIPELINE_LAYOUT) && (handleIndex < pl_.rhr.size())) {
1981        desc = GetIdDesc(pl_.nameToIndex, handleIndex);
1982    } else if ((handleType == RenderHandleType::VERTEX_INPUT_DECLARATION) && (handleIndex < shaderVid_.rhr.size())) {
1983        desc = GetIdDesc(shaderVid_.nameToIndex, handleIndex);
1984    }
1985    return desc;
1986}
1987
1988uint64_t ShaderManager::GetFrameIndex(const RenderHandleReference& handle) const
1989{
1990    const RenderHandle rawHandle = handle.GetHandle();
1991    const RenderHandleType handleType = RenderHandleUtil::GetHandleType(rawHandle);
1992    const uint32_t handleIndex = RenderHandleUtil::GetIndexPart(rawHandle);
1993    uint64_t frameIndex = 0;
1994    if ((handleType == RenderHandleType::COMPUTE_SHADER_STATE_OBJECT) ||
1995        (handleType == RenderHandleType::SHADER_STATE_OBJECT)) {
1996        frameIndex = GetShaderFrameIndex(rawHandle);
1997    } else if ((handleType == RenderHandleType::GRAPHICS_STATE) && (handleIndex < graphicsStates_.rhr.size())) {
1998        frameIndex = 0;
1999    } else if ((handleType == RenderHandleType::PIPELINE_LAYOUT) && (handleIndex < pl_.rhr.size())) {
2000        frameIndex = 0;
2001    } else if ((handleType == RenderHandleType::VERTEX_INPUT_DECLARATION) && (handleIndex < shaderVid_.rhr.size())) {
2002        frameIndex = 0;
2003    }
2004    return frameIndex;
2005}
2006
2007IShaderPipelineBinder::Ptr ShaderManager::CreateShaderPipelineBinder(
2008    const RenderHandleReference& handle, const PipelineLayout& pipelineLayout) const
2009{
2010    const RenderHandleType type = handle.GetHandleType();
2011    if (handle &&
2012        ((type == RenderHandleType::SHADER_STATE_OBJECT) || (type == RenderHandleType::COMPUTE_SHADER_STATE_OBJECT))) {
2013        return IShaderPipelineBinder::Ptr { new ShaderPipelineBinder((IShaderManager&)*this, handle, pipelineLayout) };
2014    }
2015    return nullptr;
2016}
2017
2018IShaderPipelineBinder::Ptr ShaderManager::CreateShaderPipelineBinder(
2019    const RenderHandleReference& handle, const RenderHandleReference& plHandle) const
2020{
2021    RenderHandleReference finalPlHandle = plHandle;
2022    if (!finalPlHandle) {
2023        finalPlHandle = GetPipelineLayoutHandleByShaderHandle(handle.GetHandle());
2024        if (!finalPlHandle) {
2025            finalPlHandle = GetReflectionPipelineLayoutHandle(handle.GetHandle());
2026        }
2027    }
2028    return CreateShaderPipelineBinder(handle, GetPipelineLayout(finalPlHandle));
2029}
2030
2031IShaderPipelineBinder::Ptr ShaderManager::CreateShaderPipelineBinder(const RenderHandleReference& handle) const
2032{
2033    return CreateShaderPipelineBinder(handle, RenderHandleReference {});
2034}
2035
2036ShaderManager::CompatibilityFlags ShaderManager::GetCompatibilityFlags(
2037    const RenderHandle& lhs, const RenderHandle& rhs) const
2038{
2039    const RenderHandleType lType = RenderHandleUtil::GetHandleType(lhs);
2040    const RenderHandleType rType = RenderHandleUtil::GetHandleType(rhs);
2041    CompatibilityFlags flags = 0;
2042    // NOTE: only same types supported at the moment
2043    if (lType == rType) {
2044        if (lType == RenderHandleType::PIPELINE_LAYOUT) {
2045            const PipelineLayout lpl = GetPipelineLayout(lhs);
2046            const PipelineLayout rpl = GetPipelineLayout(rhs);
2047            flags = GetPipelineLayoutCompatibilityFlags(lpl, rpl);
2048        } else if ((lType == RenderHandleType::SHADER_STATE_OBJECT) ||
2049                   (lType == RenderHandleType::COMPUTE_SHADER_STATE_OBJECT)) {
2050            // first check that given pipeline layout is valid to own reflection
2051            const RenderHandle shaderPlHandle = GetPipelineLayoutHandleByShaderHandle(rhs).GetHandle();
2052            if (RenderHandleUtil::IsValid(shaderPlHandle)) {
2053                const PipelineLayout shaderPl = GetPipelineLayout(shaderPlHandle);
2054                const PipelineLayout rpl = GetReflectionPipelineLayoutRef(rhs);
2055                if (rpl.descriptorSetCount > 0) {
2056                    flags = GetPipelineLayoutCompatibilityFlags(rpl, shaderPl);
2057                }
2058            } else {
2059                // some shaders do not specify actual pipeline layout, only shader reflection pipeline layout
2060                flags = 1u;
2061            }
2062            // then, compare to lhs with rhs reflection
2063            if (flags != 0) {
2064                const RenderHandle lShaderPlHandle = GetPipelineLayoutHandleByShaderHandle(lhs).GetHandle();
2065                const PipelineLayout lpl = RenderHandleUtil::IsValid(lShaderPlHandle)
2066                                               ? GetPipelineLayout(lShaderPlHandle)
2067                                               : GetReflectionPipelineLayoutRef(lhs);
2068                flags = GetPipelineLayoutCompatibilityFlags(lpl, GetReflectionPipelineLayoutRef(rhs));
2069            }
2070        }
2071    }
2072    return flags;
2073}
2074
2075ShaderManager::CompatibilityFlags ShaderManager::GetCompatibilityFlags(
2076    const RenderHandleReference& lhs, const RenderHandleReference& rhs) const
2077{
2078    if (lhs && rhs) {
2079        return GetCompatibilityFlags(lhs.GetHandle(), rhs.GetHandle());
2080    } else {
2081        return CompatibilityFlags { 0 };
2082    }
2083}
2084
2085GraphicsStateFlags ShaderManager::GetForcedGraphicsStateFlags(const RenderHandle& handle) const
2086{
2087    if (!RenderHandleUtil::IsValid(handle)) {
2088        return 0U; // early out
2089    }
2090
2091    const RenderHandleType type = RenderHandleUtil::GetHandleType(handle);
2092    const uint32_t arrayIndex = RenderHandleUtil::GetIndexPart(handle);
2093    GraphicsStateFlags flags { 0u };
2094
2095    uint32_t graphicsStateIndex = ~0u;
2096    if (type == RenderHandleType::GRAPHICS_STATE) {
2097        graphicsStateIndex = arrayIndex;
2098    } else if ((type == RenderHandleType::SHADER_STATE_OBJECT) &&
2099               (arrayIndex < static_cast<uint32_t>(shaderMappings_.clientData.size()))) {
2100        graphicsStateIndex = shaderMappings_.clientData[arrayIndex].graphicsStateIndex;
2101    }
2102
2103    if (graphicsStateIndex < static_cast<uint32_t>(graphicsStates_.graphicsStates.size())) {
2104        flags = graphicsStates_.data[arrayIndex].stateFlags;
2105    }
2106    return flags;
2107}
2108
2109GraphicsStateFlags ShaderManager::GetForcedGraphicsStateFlags(const RenderHandleReference& handle) const
2110{
2111    return GetForcedGraphicsStateFlags(handle.GetHandle());
2112}
2113
2114GraphicsStateFlags ShaderManager::GetForcedGraphicsStateFlags(const uint32_t renderSlotId) const
2115{
2116    if (renderSlotId < static_cast<uint32_t>(renderSlotIds_.data.size())) {
2117        return GetForcedGraphicsStateFlags(renderSlotIds_.data[renderSlotId].graphicsState.GetHandle());
2118    }
2119    return 0u;
2120}
2121
2122void ShaderManager::SetFileManager(IFileManager& fileMgr)
2123{
2124    fileMgr_ = &fileMgr;
2125    shaderLoader_ = make_unique<ShaderLoader>(*fileMgr_, *this, device_.GetBackendType());
2126}
2127
2128constexpr uint8_t REFLECTION_TAG[] = { 'r', 'f', 'l', 0 };
2129struct ReflectionHeader {
2130    uint8_t tag[sizeof(REFLECTION_TAG)];
2131    uint16_t type;
2132    uint16_t offsetPushConstants;
2133    uint16_t offsetSpecializationConstants;
2134    uint16_t offsetDescriptorSets;
2135    uint16_t offsetInputs;
2136    uint16_t offsetLocalSize;
2137};
2138
2139bool ShaderReflectionData::IsValid() const
2140{
2141    if (reflectionData.size() < sizeof(ReflectionHeader)) {
2142        return false;
2143    }
2144    const ReflectionHeader& header = *reinterpret_cast<const ReflectionHeader*>(reflectionData.data());
2145    return memcmp(header.tag, REFLECTION_TAG, sizeof(REFLECTION_TAG)) == 0;
2146}
2147
2148ShaderStageFlags ShaderReflectionData::GetStageFlags() const
2149{
2150    ShaderStageFlags flags;
2151    const ReflectionHeader& header = *reinterpret_cast<const ReflectionHeader*>(reflectionData.data());
2152    flags = header.type;
2153    return flags;
2154}
2155
2156PipelineLayout ShaderReflectionData::GetPipelineLayout() const
2157{
2158    PipelineLayout pipelineLayout;
2159    const ReflectionHeader& header = *reinterpret_cast<const ReflectionHeader*>(reflectionData.data());
2160    if (header.offsetPushConstants && header.offsetPushConstants < reflectionData.size()) {
2161        auto ptr = reflectionData.data() + header.offsetPushConstants;
2162        const auto constants = *ptr;
2163        if (constants) {
2164            pipelineLayout.pushConstant.shaderStageFlags = header.type;
2165            pipelineLayout.pushConstant.byteSize = static_cast<uint32_t>(*(ptr + 1) | (*(ptr + 2) << 8));
2166        }
2167    }
2168    if (header.offsetDescriptorSets && header.offsetDescriptorSets < reflectionData.size()) {
2169        auto ptr = reflectionData.data() + header.offsetDescriptorSets;
2170        pipelineLayout.descriptorSetCount = static_cast<uint32_t>(*(ptr) | (*(ptr + 1) << 8));
2171        ptr += 2;
2172        for (auto i = 0u; i < pipelineLayout.descriptorSetCount; ++i) {
2173            // write to correct set location
2174            const uint32_t set = static_cast<uint32_t>(*ptr | (*(ptr + 1) << 8));
2175            PLUGIN_ASSERT(set < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT);
2176            auto& layout = pipelineLayout.descriptorSetLayouts[set];
2177            layout.set = set;
2178            ptr += 2;
2179            const auto bindings = static_cast<uint32_t>(*ptr | (*(ptr + 1) << 8));
2180            ptr += 2;
2181            for (auto j = 0u; j < bindings; ++j) {
2182                DescriptorSetLayoutBinding binding;
2183                binding.binding = static_cast<uint32_t>(*ptr | (*(ptr + 1) << 8));
2184                ptr += 2;
2185                binding.descriptorType = static_cast<DescriptorType>(*ptr | (*(ptr + 1) << 8));
2186                if ((binding.descriptorType > DescriptorType::CORE_DESCRIPTOR_TYPE_INPUT_ATTACHMENT) &&
2187                    (binding.descriptorType ==
2188                        (DescriptorType::CORE_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE & 0xffff))) {
2189                    binding.descriptorType = DescriptorType::CORE_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE;
2190                }
2191                ptr += 2;
2192                binding.descriptorCount = static_cast<uint32_t>(*ptr | (*(ptr + 1) << 8));
2193                ptr += 2;
2194                binding.shaderStageFlags = header.type;
2195                layout.bindings.push_back(binding);
2196            }
2197        }
2198    }
2199    return pipelineLayout;
2200}
2201
2202vector<ShaderSpecialization::Constant> ShaderReflectionData::GetSpecializationConstants() const
2203{
2204    vector<ShaderSpecialization::Constant> constants;
2205    const ReflectionHeader& header = *reinterpret_cast<const ReflectionHeader*>(reflectionData.data());
2206    if (header.offsetSpecializationConstants && header.offsetSpecializationConstants < reflectionData.size()) {
2207        auto ptr = reflectionData.data() + header.offsetSpecializationConstants;
2208        const auto size = *ptr | *(ptr + 1) << 8 | *(ptr + 2) << 16 | *(ptr + 3) << 24;
2209        ptr += 4;
2210        for (auto i = 0; i < size; ++i) {
2211            ShaderSpecialization::Constant constant;
2212            constant.shaderStage = header.type;
2213            constant.id = static_cast<uint32_t>(*ptr | *(ptr + 1) << 8 | *(ptr + 2) << 16 | *(ptr + 3) << 24);
2214            ptr += 4;
2215            constant.type = static_cast<ShaderSpecialization::Constant::Type>(
2216                *ptr | *(ptr + 1) << 8 | *(ptr + 2) << 16 | *(ptr + 3) << 24);
2217            ptr += 4;
2218            constant.offset = 0;
2219            constants.push_back(constant);
2220        }
2221    }
2222    return constants;
2223}
2224
2225vector<VertexInputDeclaration::VertexInputAttributeDescription> ShaderReflectionData::GetInputDescriptions() const
2226{
2227    vector<VertexInputDeclaration::VertexInputAttributeDescription> inputs;
2228    const ReflectionHeader& header = *reinterpret_cast<const ReflectionHeader*>(reflectionData.data());
2229    if (header.offsetInputs && header.offsetInputs < reflectionData.size()) {
2230        auto ptr = reflectionData.data() + header.offsetInputs;
2231        const auto size = *(ptr) | (*(ptr + 1) << 8);
2232        ptr += 2;
2233        for (auto i = 0; i < size; ++i) {
2234            VertexInputDeclaration::VertexInputAttributeDescription desc;
2235            desc.location = static_cast<uint32_t>(*(ptr) | (*(ptr + 1) << 8));
2236            ptr += 2;
2237            desc.binding = desc.location;
2238            desc.format = static_cast<Format>(*(ptr) | (*(ptr + 1) << 8));
2239            ptr += 2;
2240            desc.offset = 0;
2241            inputs.push_back(desc);
2242        }
2243    }
2244    return inputs;
2245}
2246
2247Math::UVec3 ShaderReflectionData::GetLocalSize() const
2248{
2249    Math::UVec3 sizes;
2250    const ReflectionHeader& header = *reinterpret_cast<const ReflectionHeader*>(reflectionData.data());
2251    if (header.offsetLocalSize && header.offsetLocalSize < reflectionData.size()) {
2252        auto ptr = reflectionData.data() + header.offsetLocalSize;
2253        sizes.x = static_cast<uint32_t>(*ptr | (*(ptr + 1) << 8) | (*(ptr + 2)) << 16 | (*(ptr + 3)) << 24);
2254        ptr += 4;
2255        sizes.y = static_cast<uint32_t>(*ptr | (*(ptr + 1) << 8) | (*(ptr + 2)) << 16 | (*(ptr + 3)) << 24);
2256        ptr += 4;
2257        sizes.z = static_cast<uint32_t>(*ptr | (*(ptr + 1) << 8) | (*(ptr + 2)) << 16 | (*(ptr + 3)) << 24);
2258    }
2259    return sizes;
2260}
2261
2262const uint8_t* ShaderReflectionData::GetPushConstants() const
2263{
2264    const uint8_t* ptr = nullptr;
2265    const ReflectionHeader& header = *reinterpret_cast<const ReflectionHeader*>(reflectionData.data());
2266    if (header.offsetPushConstants && header.offsetPushConstants < reflectionData.size()) {
2267        const auto constants = *(reflectionData.data() + header.offsetPushConstants);
2268        if (constants) {
2269            // number of constants is uint8 and the size of the constant is uint16
2270            ptr = reflectionData.data() + header.offsetPushConstants + sizeof(uint8_t) + sizeof(uint16_t);
2271        }
2272    }
2273    return ptr;
2274}
2275
2276RenderNodeShaderManager::RenderNodeShaderManager(const ShaderManager& shaderMgr) : shaderMgr_(shaderMgr) {}
2277
2278RenderHandle RenderNodeShaderManager::GetShaderHandle(const string_view path) const
2279{
2280    return shaderMgr_.GetShaderHandle(path).GetHandle();
2281}
2282
2283RenderHandle RenderNodeShaderManager::GetShaderHandle(const string_view path, const string_view variantName) const
2284{
2285    return shaderMgr_.GetShaderHandle(path, variantName).GetHandle();
2286}
2287
2288RenderHandle RenderNodeShaderManager::GetShaderHandle(const RenderHandle& handle, const uint32_t renderSlotId) const
2289{
2290    return shaderMgr_.GetShaderHandle(handle, renderSlotId).GetHandle();
2291}
2292
2293vector<RenderHandle> RenderNodeShaderManager::GetShaders(const uint32_t renderSlotId) const
2294{
2295    return shaderMgr_.GetShaderRawHandles(renderSlotId);
2296}
2297
2298RenderHandle RenderNodeShaderManager::GetGraphicsStateHandle(const string_view path) const
2299{
2300    return shaderMgr_.GetGraphicsStateHandle(path).GetHandle();
2301}
2302
2303RenderHandle RenderNodeShaderManager::GetGraphicsStateHandle(
2304    const string_view path, const string_view variantName) const
2305{
2306    return shaderMgr_.GetGraphicsStateHandle(path, variantName).GetHandle();
2307}
2308
2309RenderHandle RenderNodeShaderManager::GetGraphicsStateHandle(
2310    const RenderHandle& handle, const uint32_t renderSlotId) const
2311{
2312    return shaderMgr_.GetGraphicsStateHandle(handle, renderSlotId).GetHandle();
2313}
2314
2315RenderHandle RenderNodeShaderManager::GetGraphicsStateHandleByHash(const uint64_t hash) const
2316{
2317    return shaderMgr_.GetGraphicsStateHandleByHash(hash).GetHandle();
2318}
2319
2320RenderHandle RenderNodeShaderManager::GetGraphicsStateHandleByShaderHandle(const RenderHandle& handle) const
2321{
2322    return shaderMgr_.GetGraphicsStateHandleByShaderHandle(handle).GetHandle();
2323}
2324
2325const GraphicsState& RenderNodeShaderManager::GetGraphicsState(const RenderHandle& handle) const
2326{
2327    return shaderMgr_.GetGraphicsStateRef(handle);
2328}
2329
2330uint32_t RenderNodeShaderManager::GetRenderSlotId(const string_view renderSlot) const
2331{
2332    return shaderMgr_.GetRenderSlotId(renderSlot);
2333}
2334
2335uint32_t RenderNodeShaderManager::GetRenderSlotId(const RenderHandle& handle) const
2336{
2337    return shaderMgr_.GetRenderSlotId(handle);
2338}
2339
2340IShaderManager::RenderSlotData RenderNodeShaderManager::GetRenderSlotData(const uint32_t renderSlotId) const
2341{
2342    return shaderMgr_.GetRenderSlotData(renderSlotId);
2343}
2344
2345RenderHandle RenderNodeShaderManager::GetVertexInputDeclarationHandleByShaderHandle(const RenderHandle& handle) const
2346{
2347    return shaderMgr_.GetVertexInputDeclarationHandleByShaderHandle(handle).GetHandle();
2348}
2349
2350RenderHandle RenderNodeShaderManager::GetVertexInputDeclarationHandle(const string_view path) const
2351{
2352    return shaderMgr_.GetVertexInputDeclarationHandle(path).GetHandle();
2353}
2354
2355VertexInputDeclarationView RenderNodeShaderManager::GetVertexInputDeclarationView(const RenderHandle& handle) const
2356{
2357    return shaderMgr_.GetVertexInputDeclarationView(handle);
2358}
2359
2360RenderHandle RenderNodeShaderManager::GetPipelineLayoutHandleByShaderHandle(const RenderHandle& handle) const
2361{
2362    return shaderMgr_.GetPipelineLayoutHandleByShaderHandle(handle).GetHandle();
2363}
2364
2365const PipelineLayout& RenderNodeShaderManager::GetPipelineLayout(const RenderHandle& handle) const
2366{
2367    return shaderMgr_.GetPipelineLayoutRef(handle);
2368}
2369
2370RenderHandle RenderNodeShaderManager::GetPipelineLayoutHandle(const string_view path) const
2371{
2372    return shaderMgr_.GetPipelineLayoutHandle(path).GetHandle();
2373}
2374
2375RenderHandle RenderNodeShaderManager::GetReflectionPipelineLayoutHandle(const RenderHandle& handle) const
2376{
2377    return shaderMgr_.GetReflectionPipelineLayoutHandle(handle).GetHandle();
2378}
2379
2380const PipelineLayout& RenderNodeShaderManager::GetReflectionPipelineLayout(const RenderHandle& handle) const
2381{
2382    return shaderMgr_.GetReflectionPipelineLayoutRef(handle);
2383}
2384
2385ShaderSpecializationConstantView RenderNodeShaderManager::GetReflectionSpecialization(const RenderHandle& handle) const
2386{
2387    return shaderMgr_.GetReflectionSpecialization(handle);
2388}
2389
2390VertexInputDeclarationView RenderNodeShaderManager::GetReflectionVertexInputDeclaration(
2391    const RenderHandle& handle) const
2392{
2393    return shaderMgr_.GetReflectionVertexInputDeclaration(handle);
2394}
2395
2396ShaderThreadGroup RenderNodeShaderManager::GetReflectionThreadGroupSize(const RenderHandle& handle) const
2397{
2398    return shaderMgr_.GetReflectionThreadGroupSize(handle);
2399}
2400
2401uint64_t RenderNodeShaderManager::HashGraphicsState(const GraphicsState& graphicsState) const
2402{
2403    return shaderMgr_.HashGraphicsState(graphicsState);
2404}
2405
2406bool RenderNodeShaderManager::IsValid(const RenderHandle& handle) const
2407{
2408    return RenderHandleUtil::IsValid(handle);
2409}
2410
2411bool RenderNodeShaderManager::IsComputeShader(const RenderHandle& handle) const
2412{
2413    return IsComputeShaderFunc(handle);
2414}
2415
2416bool RenderNodeShaderManager::IsShader(const RenderHandle& handle) const
2417{
2418    return IsShaderFunc(handle);
2419}
2420
2421vector<RenderHandle> RenderNodeShaderManager::GetShaders(
2422    const RenderHandle& handle, const ShaderStageFlags shaderStageFlags) const
2423{
2424    return shaderMgr_.GetShaders(handle, shaderStageFlags);
2425}
2426
2427IShaderManager::CompatibilityFlags RenderNodeShaderManager::GetCompatibilityFlags(
2428    const RenderHandle& lhs, const RenderHandle& rhs) const
2429{
2430    return shaderMgr_.GetCompatibilityFlags(lhs, rhs);
2431}
2432
2433GraphicsStateFlags RenderNodeShaderManager::GetForcedGraphicsStateFlags(const RenderHandle& handle) const
2434{
2435    return shaderMgr_.GetForcedGraphicsStateFlags(handle);
2436}
2437
2438GraphicsStateFlags RenderNodeShaderManager::GetForcedGraphicsStateFlags(const uint32_t renderSlotId) const
2439{
2440    return shaderMgr_.GetForcedGraphicsStateFlags(renderSlotId);
2441}
2442RENDER_END_NAMESPACE()
2443