• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "shader.h"
16 
17 #include <algorithm>
18 #include <mutex>
19 #include <scene/ext/util.h>
20 
21 #include <3d/render/default_material_constants.h>
22 #include <render/device/intf_gpu_resource_manager.h>
23 
24 #include "util.h"
25 
SCENE_BEGIN_NAMESPACE()26 SCENE_BEGIN_NAMESPACE()
27 
28 bool GraphicsState::SetGraphicsState(RENDER_NS::RenderHandleReference handle)
29 {
30     std::unique_lock lock { mutex_ };
31     graphicsState_ = handle;
32     return true;
33 }
GetGraphicsState() const34 RENDER_NS::RenderHandleReference GraphicsState::GetGraphicsState() const
35 {
36     std::shared_lock lock { mutex_ };
37     return graphicsState_;
38 }
39 
IsBlendEnabled(const RENDER_NS::GraphicsState & gs)40 static bool IsBlendEnabled(const RENDER_NS::GraphicsState& gs)
41 {
42     return std::any_of(gs.colorBlendState.colorAttachments,
43         gs.colorBlendState.colorAttachments + gs.colorBlendState.colorAttachmentCount,
44         [](const RENDER_NS::GraphicsState::ColorBlendState::Attachment& attachment) { return attachment.enableBlend; });
45 }
46 
GetRenderSlot(const RENDER_NS::GraphicsState & gs)47 static BASE_NS::string_view GetRenderSlot(const RENDER_NS::GraphicsState& gs)
48 {
49     return IsBlendEnabled(gs) ? CORE3D_NS::DefaultMaterialShaderConstants::RENDER_SLOT_FORWARD_TRANSLUCENT
50                               : CORE3D_NS::DefaultMaterialShaderConstants::RENDER_SLOT_FORWARD_OPAQUE;
51 }
52 
CreateGraphicsState(const IRenderContext::Ptr & context,RENDER_NS::RenderHandleReference state,BASE_NS::string_view defaultRenderSlot)53 RENDER_NS::GraphicsState GraphicsState::CreateGraphicsState(
54     const IRenderContext::Ptr& context, RENDER_NS::RenderHandleReference state, BASE_NS::string_view defaultRenderSlot)
55 {
56     auto& man = context->GetRenderer()->GetDevice().GetShaderManager();
57     RENDER_NS::GraphicsState gs;
58     RENDER_NS::IShaderManager::GraphicsStateVariantCreateInfo vinfo;
59     if (state) {
60         gs = man.GetGraphicsState(state);
61         auto id = man.GetRenderSlotId(state);
62         vinfo.renderSlot = man.GetRenderSlotName(id);
63     } else {
64         auto renderSlotId = man.GetRenderSlotId(defaultRenderSlot);
65         auto rsd = man.GetRenderSlotData(renderSlotId);
66         gs = man.GetGraphicsState(rsd.graphicsState);
67         vinfo.renderSlot = GetRenderSlot(gs);
68     }
69     std::unique_lock lock { mutex_ };
70     graphicsState_ =
71         man.CreateGraphicsState({ "SceneGS_" + BASE_NS::string(BASE_NS::to_string(uintptr_t(this))), gs }, vinfo);
72     return gs;
73 }
74 
UpdateGraphicsState(const IRenderContext::Ptr & context,const RENDER_NS::GraphicsState & gs,BASE_NS::string_view renderSlot={})75 bool GraphicsState::UpdateGraphicsState(
76     const IRenderContext::Ptr& context, const RENDER_NS::GraphicsState& gs, BASE_NS::string_view renderSlot = {})
77 {
78     auto& man = context->GetRenderer()->GetDevice().GetShaderManager();
79     RENDER_NS::IShaderManager::GraphicsStateVariantCreateInfo vinfo { renderSlot };
80     if (renderSlot.empty()) {
81         vinfo.renderSlot = GetRenderSlot(gs);
82     }
83     auto s = man.CreateGraphicsState({ "SceneGS_" + BASE_NS::string(BASE_NS::to_string(uintptr_t(this))), gs }, vinfo);
84     {
85         bool update = false;
86         {
87             std::unique_lock lock { mutex_ };
88             update = s.GetHandle() != graphicsState_.GetHandle();
89             if (update) {
90                 graphicsState_ = s;
91             }
92         }
93         if (update) {
94             if (auto ev = EventOnResourceChanged(META_NS::MetadataQuery::EXISTING)) {
95                 META_NS::Invoke<META_NS::IOnChanged>(ev);
96             }
97         }
98     }
99     return true;
100 }
101 
CreateNewGraphicsState(const IRenderContext::Ptr & context,bool blend)102 RENDER_NS::GraphicsState GraphicsState::CreateNewGraphicsState(const IRenderContext::Ptr& context, bool blend)
103 {
104     // notice: this is wrong for user shaders, fix later
105     auto& man = context->GetRenderer()->GetDevice().GetShaderManager();
106     auto oldgs = GetGraphicsState(context);
107     auto renderSlotId =
108         man.GetRenderSlotId(blend ? CORE3D_NS::DefaultMaterialShaderConstants::RENDER_SLOT_FORWARD_TRANSLUCENT
109                                   : CORE3D_NS::DefaultMaterialShaderConstants::RENDER_SLOT_FORWARD_OPAQUE);
110     auto rsd = man.GetRenderSlotData(renderSlotId);
111     auto gs = man.GetGraphicsState(rsd.graphicsState);
112     gs.inputAssembly = oldgs.inputAssembly;
113     gs.depthStencilState = oldgs.depthStencilState;
114     gs.rasterizationState = oldgs.rasterizationState;
115     return gs;
116 }
117 
GetGraphicsState(const IRenderContext::Ptr & context) const118 RENDER_NS::GraphicsState GraphicsState::GetGraphicsState(const IRenderContext::Ptr& context) const
119 {
120     auto& man = context->GetRenderer()->GetDevice().GetShaderManager();
121     std::shared_lock lock { mutex_ };
122     return man.GetGraphicsState(graphicsState_);
123 }
124 
GetName() const125 BASE_NS::string Shader::GetName() const
126 {
127     return META_NS::GetValue(Name());
128 }
129 
SetRenderHandle(RENDER_NS::RenderHandleReference handle)130 bool Shader::SetRenderHandle(RENDER_NS::RenderHandleReference handle)
131 {
132     return SetShaderState(handle, {});
133 }
134 
SetShaderState(RENDER_NS::RenderHandleReference shader,RENDER_NS::RenderHandleReference graphics)135 bool Shader::SetShaderState(RENDER_NS::RenderHandleReference shader, RENDER_NS::RenderHandleReference graphics)
136 {
137     IRenderContext::Ptr context = context_.lock();
138     if (!context) {
139         CORE_LOG_E("Invalid context");
140         return false;
141     }
142     RENDER_NS::IShaderManager::IdDesc desc;
143     RENDER_NS::GraphicsState gs;
144     BASE_NS::string renderSlot;
145     context
146         ->AddTask([&] {
147             renderSlot = CORE3D_NS::DefaultMaterialShaderConstants::RENDER_SLOT_FORWARD_OPAQUE;
148             if (shader) {
149                 desc = context->GetRenderer()->GetDevice().GetShaderManager().GetIdDesc(shader);
150                 renderSlot = desc.renderSlot;
151             }
152             gs = CreateGraphicsState(context, graphics, renderSlot);
153         })
154         .Wait();
155 
156     {
157         std::unique_lock lock { mutex_ };
158         handle_ = shader;
159     }
160 
161     // todo: notify in same thread?
162     setShaderStateInProgress_ = true;
163     Name()->SetValue(desc.displayName);
164     CullMode()->SetValue(static_cast<CullModeFlags>(gs.rasterizationState.cullModeFlags));
165     Blend()->SetValue(IsBlendEnabled(gs));
166     setShaderStateInProgress_ = false;
167     UpdateGraphicsState(context, gs, renderSlot);
168     if (auto ev = EventOnResourceChanged(META_NS::MetadataQuery::EXISTING)) {
169         META_NS::Invoke<META_NS::IOnChanged>(ev);
170     }
171 
172     return true;
173 }
174 
OnPropertyChanged(const META_NS::IProperty & p)175 void Shader::OnPropertyChanged(const META_NS::IProperty& p)
176 {
177     if (setShaderStateInProgress_) {
178         // ignore the property sets during SetShaderState.
179         return;
180     }
181     auto context = context_.lock();
182     auto state = GetGraphicsState();
183     if (!context || !state) {
184         return;
185     }
186     if (p.GetName() == "CullMode") {
187         context
188             ->AddTask([&] {
189                 auto gs = GetGraphicsState(context);
190                 gs.rasterizationState.cullModeFlags = static_cast<RENDER_NS::CullModeFlags>(CullMode()->GetValue());
191                 UpdateGraphicsState(context, gs);
192             })
193             .Wait();
194     } else if (p.GetName() == "Blend") {
195         context->AddTask([&] { UpdateGraphicsState(context, CreateNewGraphicsState(context, Blend()->GetValue())); })
196             .Wait();
197     }
198 }
199 
200 SCENE_END_NAMESPACE()
201