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.h"
17
18 #include <algorithm>
19 #include <3d/render/default_material_constants.h>
20 #include <render/device/intf_gpu_resource_manager.h>
21
22 #include <meta/api/make_callback.h>
23
24 #include "../util.h"
25
SCENE_BEGIN_NAMESPACE()26 SCENE_BEGIN_NAMESPACE()
27
28 BASE_NS::string Shader::GetName() const
29 {
30 return Name()->GetValue();
31 }
32
SetRenderHandleImpl(const IInternalScene::Ptr & scene,RENDER_NS::RenderHandleReference handle)33 bool Shader::SetRenderHandleImpl(const IInternalScene::Ptr& scene, RENDER_NS::RenderHandleReference handle)
34 {
35 handle_ = handle;
36 return true;
37 }
38
SetRenderHandle(const IInternalScene::Ptr & scene,RENDER_NS::RenderHandleReference handle,CORE_NS::EntityReference ent)39 bool Shader::SetRenderHandle(
40 const IInternalScene::Ptr& scene, RENDER_NS::RenderHandleReference handle, CORE_NS::EntityReference ent)
41 {
42 return SetShaderState(scene, handle, ent, {}, {});
43 }
44
SetShaderState(const IInternalScene::Ptr & scene,RENDER_NS::RenderHandleReference handle,CORE_NS::EntityReference ent,RENDER_NS::RenderHandleReference ghandle,CORE_NS::EntityReference gstate)45 bool Shader::SetShaderState(const IInternalScene::Ptr& scene, RENDER_NS::RenderHandleReference handle,
46 CORE_NS::EntityReference ent, RENDER_NS::RenderHandleReference ghandle, CORE_NS::EntityReference gstate)
47 {
48 {
49 std::shared_lock lock { mutex_ };
50 if (handle_.GetHandle() == handle.GetHandle() && entity_ == ent && graphicsState_ == gstate &&
51 graphicsStateHandle_.GetHandle() == ghandle.GetHandle()) {
52 return true;
53 }
54 }
55
56 RENDER_NS::IShaderManager::IdDesc desc;
57 scene
58 ->AddTask([&] {
59 auto& shaderMgr = scene->GetRenderContext().GetDevice().GetShaderManager();
60
61 if (auto rhman = static_cast<CORE3D_NS::IRenderHandleComponentManager*>(
62 scene->GetEcsContext().FindComponent<CORE3D_NS::RenderHandleComponent>())) {
63 auto renderSlotId =
64 shaderMgr.GetRenderSlotId(CORE3D_NS::DefaultMaterialShaderConstants::RENDER_SLOT_FORWARD_OPAQUE);
65 auto rsd = shaderMgr.GetRenderSlotData(renderSlotId);
66
67 if (handle) {
68 if (!ent) {
69 ent = HandleFromRenderResource(scene, handle);
70 }
71 desc = shaderMgr.GetIdDesc(handle);
72 } else {
73 desc = shaderMgr.GetIdDesc(rsd.shader);
74 }
75 if (!ghandle) {
76 ghandle = UpdateGraphicsState(scene, shaderMgr.GetGraphicsState(rsd.graphicsState));
77 }
78 if (!gstate) {
79 gstate = HandleFromRenderResource(scene, ghandle);
80 }
81 if (auto m = rhman->Write(gstate)) {
82 m->reference = ghandle;
83 }
84 }
85 })
86 .Wait();
87
88 {
89 std::unique_lock lock { mutex_ };
90 handle_ = handle;
91 entity_ = ent;
92 graphicsState_ = gstate;
93 graphicsStateHandle_ = ghandle;
94 scene_ = scene;
95 }
96 META_ACCESS_PROPERTY(Uri)->SetValue(desc.path);
97 META_ACCESS_PROPERTY(Name)->SetValue(desc.displayName);
98 META_NS::Invoke<META_NS::IOnChanged>(EventOnResourceChanged(META_NS::MetadataQuery::EXISTING));
99 return true;
100 }
GetRenderHandle() const101 RENDER_NS::RenderHandleReference Shader::GetRenderHandle() const
102 {
103 std::shared_lock lock { mutex_ };
104 return handle_;
105 }
GetEntity() const106 CORE_NS::Entity Shader::GetEntity() const
107 {
108 std::shared_lock lock { mutex_ };
109 return entity_;
110 }
111
SetGraphicsState(CORE_NS::EntityReference gstate)112 bool Shader::SetGraphicsState(CORE_NS::EntityReference gstate)
113 {
114 std::unique_lock lock { mutex_ };
115 graphicsState_ = gstate;
116 return true;
117 }
GetGraphicsState() const118 CORE_NS::EntityReference Shader::GetGraphicsState() const
119 {
120 std::shared_lock lock { mutex_ };
121 return graphicsState_;
122 }
123
LoadShader(const IScene::Ptr & s,BASE_NS::string_view uri)124 Future<bool> Shader::LoadShader(const IScene::Ptr& s, BASE_NS::string_view uri)
125 {
126 if (auto inter = s->GetInternalScene()) {
127 return inter->AddTask([=, path = BASE_NS::string(uri)] {
128 auto& man = inter->GetRenderContext().GetDevice().GetShaderManager();
129 man.LoadShaderFile(path);
130 auto handle = man.GetShaderHandle(path);
131 if (handle) {
132 // t: notify in correct thread
133 SetShaderState(inter, handle, {}, man.GetGraphicsStateHandleByShaderHandle(handle), {});
134 }
135 return static_cast<bool>(handle);
136 });
137 }
138 return {};
139 }
140
GetScene() const141 IInternalScene::Ptr Shader::GetScene() const
142 {
143 std::shared_lock lock { mutex_ };
144 return scene_.lock();
145 }
146
GetGraphicsStateHandle() const147 RENDER_NS::RenderHandleReference Shader::GetGraphicsStateHandle() const
148 {
149 std::shared_lock lock { mutex_ };
150 return graphicsStateHandle_;
151 }
152
GetRenderSlot(const RENDER_NS::GraphicsState & gs)153 static BASE_NS::string_view GetRenderSlot(const RENDER_NS::GraphicsState& gs)
154 {
155 return std::any_of(gs.colorBlendState.colorAttachments,
156 gs.colorBlendState.colorAttachments + gs.colorBlendState.colorAttachmentCount,
157 [](const RENDER_NS::GraphicsState::ColorBlendState::Attachment& attachment) {
158 return attachment.enableBlend;
159 })
160 ? CORE3D_NS::DefaultMaterialShaderConstants::RENDER_SLOT_FORWARD_TRANSLUCENT
161 : CORE3D_NS::DefaultMaterialShaderConstants::RENDER_SLOT_FORWARD_OPAQUE;
162 }
163
UpdateGraphicsState(const IInternalScene::Ptr & scene,const RENDER_NS::GraphicsState & gs)164 RENDER_NS::RenderHandleReference Shader::UpdateGraphicsState(
165 const IInternalScene::Ptr& scene, const RENDER_NS::GraphicsState& gs)
166 {
167 auto& man = scene->GetRenderContext().GetDevice().GetShaderManager();
168 RENDER_NS::IShaderManager::GraphicsStateVariantCreateInfo vinfo { GetRenderSlot(gs) };
169 auto handle = man.CreateGraphicsState({ BASE_NS::string(BASE_NS::to_string(intptr_t(this))), gs }, vinfo);
170 std::unique_lock lock { mutex_ };
171 if (graphicsStateHandle_.GetHandle() != handle.GetHandle()) {
172 if (auto rhman = static_cast<CORE3D_NS::IRenderHandleComponentManager*>(
173 scene->GetEcsContext().FindComponent<CORE3D_NS::RenderHandleComponent>())) {
174 graphicsStateHandle_ = handle;
175 if (auto m = rhman->Write(graphicsState_)) {
176 m->reference = graphicsStateHandle_;
177 }
178 }
179 }
180 return graphicsStateHandle_;
181 }
182
GetCullMode() const183 Future<CullModeFlags> Shader::GetCullMode() const
184 {
185 if (auto inter = GetScene()) {
186 return inter->AddTask([=] {
187 if (auto h = GetGraphicsStateHandle()) {
188 auto& man = inter->GetRenderContext().GetDevice().GetShaderManager();
189 auto gs = man.GetGraphicsState(h);
190 return static_cast<CullModeFlags>(gs.rasterizationState.cullModeFlags);
191 }
192 return CullModeFlags {};
193 });
194 }
195 return {};
196 }
197
SetCullMode(CullModeFlags cullMode)198 Future<bool> Shader::SetCullMode(CullModeFlags cullMode)
199 {
200 if (auto inter = GetScene()) {
201 return inter->AddTask([=] {
202 auto h = GetGraphicsStateHandle();
203 if (h) {
204 auto& man = inter->GetRenderContext().GetDevice().GetShaderManager();
205 auto gs = man.GetGraphicsState(h);
206 gs.rasterizationState.cullModeFlags = static_cast<RENDER_NS::CullModeFlags>(cullMode);
207 UpdateGraphicsState(inter, gs);
208 }
209 return static_cast<bool>(h);
210 });
211 }
212 return {};
213 }
214
IsBlendEnabled() const215 Future<bool> Shader::IsBlendEnabled() const
216 {
217 if (auto inter = GetScene()) {
218 return inter->AddTask([=] {
219 if (auto h = GetGraphicsStateHandle()) {
220 auto& man = inter->GetRenderContext().GetDevice().GetShaderManager();
221 auto gs = man.GetGraphicsState(h);
222 if (gs.colorBlendState.colorAttachmentCount) {
223 return static_cast<bool>(gs.colorBlendState.colorAttachments[0].enableBlend);
224 }
225 }
226 return bool {};
227 });
228 }
229 return {};
230 }
231
EnableBlend(bool enableBlend)232 Future<bool> Shader::EnableBlend(bool enableBlend)
233 {
234 if (auto inter = GetScene()) {
235 return inter->AddTask([=] {
236 auto h = GetGraphicsStateHandle();
237 if (h) {
238 auto& shaderMgr = inter->GetRenderContext().GetDevice().GetShaderManager();
239 auto oldgs = shaderMgr.GetGraphicsState(h);
240 auto renderSlotId = shaderMgr.GetRenderSlotId(
241 enableBlend ? CORE3D_NS::DefaultMaterialShaderConstants::RENDER_SLOT_FORWARD_TRANSLUCENT
242 : CORE3D_NS::DefaultMaterialShaderConstants::RENDER_SLOT_FORWARD_OPAQUE);
243 auto rsd = shaderMgr.GetRenderSlotData(renderSlotId);
244
245 auto gs = shaderMgr.GetGraphicsState(rsd.graphicsState);
246 gs.rasterizationState.cullModeFlags = oldgs.rasterizationState.cullModeFlags;
247
248 if (gs.colorBlendState.colorAttachmentCount == 0) {
249 gs.colorBlendState.colorAttachmentCount = 1;
250 }
251 gs.colorBlendState.colorAttachments[0].enableBlend = enableBlend;
252
253 UpdateGraphicsState(inter, gs);
254 }
255 return static_cast<bool>(h);
256 });
257 }
258 return {};
259 }
260
261 SCENE_END_NAMESPACE()
262