1 /*
2 * Copyright (c) 2022 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 "render_data_store_default_light.h"
17
18 #include <cstdint>
19
20 #include <3d/render/default_material_constants.h>
21 #include <3d/render/render_data_defines_3d.h>
22 #include <base/containers/array_view.h>
23 #include <core/log.h>
24 #include <render/resource_handle.h>
25
26 CORE3D_BEGIN_NAMESPACE()
27 using namespace BASE_NS;
28 using namespace RENDER_NS;
29
RenderDataStoreDefaultLight(const string_view name)30 RenderDataStoreDefaultLight::RenderDataStoreDefaultLight(const string_view name) : name_(name) {}
31
PostRender()32 void RenderDataStoreDefaultLight::PostRender()
33 {
34 Clear();
35 }
36
Clear()37 void RenderDataStoreDefaultLight::Clear()
38 {
39 lights_.clear();
40 lightCounts_ = {};
41 }
42
Ref()43 void RenderDataStoreDefaultLight::Ref()
44 {
45 refcnt_.fetch_add(1, std::memory_order_relaxed);
46 }
47
Unref()48 void RenderDataStoreDefaultLight::Unref()
49 {
50 if (std::atomic_fetch_sub_explicit(&refcnt_, 1, std::memory_order_release) == 1) {
51 std::atomic_thread_fence(std::memory_order_acquire);
52 delete this;
53 }
54 }
55
GetRefCount()56 int32_t RenderDataStoreDefaultLight::GetRefCount()
57 {
58 return refcnt_;
59 }
60
SetShadowTypes(const ShadowTypes & shadowTypes,const uint32_t flags)61 void RenderDataStoreDefaultLight::SetShadowTypes(const ShadowTypes& shadowTypes, const uint32_t flags)
62 {
63 shadowTypes_ = shadowTypes;
64 }
65
GetShadowTypes() const66 IRenderDataStoreDefaultLight::ShadowTypes RenderDataStoreDefaultLight::GetShadowTypes() const
67 {
68 return shadowTypes_;
69 }
70
SetShadowQualityResolutions(const ShadowQualityResolutions & resolutions,const uint32_t flags)71 void RenderDataStoreDefaultLight::SetShadowQualityResolutions(
72 const ShadowQualityResolutions& resolutions, const uint32_t flags)
73 {
74 resolutions_ = resolutions;
75 }
76
GetShadowQualityResolution() const77 Math::UVec2 RenderDataStoreDefaultLight::GetShadowQualityResolution() const
78 {
79 if (shadowTypes_.shadowQuality == ShadowQuality::LOW) {
80 return resolutions_.low;
81 } else if (shadowTypes_.shadowQuality == ShadowQuality::NORMAL) {
82 return resolutions_.normal;
83 } else if (shadowTypes_.shadowQuality == ShadowQuality::HIGH) {
84 return resolutions_.high;
85 } else {
86 return resolutions_.ultra;
87 }
88 }
89
AddLight(const RenderLight & light)90 void RenderDataStoreDefaultLight::AddLight(const RenderLight& light)
91 {
92 // drop light that has all components below zero (negative light)
93 constexpr float lightIntensityEpsilon { 0.0001f };
94 if (((light.color.x < 0.0f) && (light.color.y < 0.0f) && (light.color.z < 0.0f)) ||
95 (light.color.w < lightIntensityEpsilon)) {
96 return;
97 }
98
99 RenderLight renderLight = light; // copy
100 // we do not support negative color values for lights
101 renderLight.color.x = Math::max(0.0f, renderLight.color.x);
102 renderLight.color.y = Math::max(0.0f, renderLight.color.y);
103 renderLight.color.z = Math::max(0.0f, renderLight.color.z);
104 const uint32_t lightCount = lightCounts_.directional + lightCounts_.spot + lightCounts_.point;
105 if (lightCount >= DefaultMaterialLightingConstants::MAX_LIGHT_COUNT) {
106 #if (CORE3D_VALIDATION_ENABLED == 1)
107 CORE_LOG_ONCE_W("drop_light_count_", "CORE3D_VALIDATION: light dropped (max count: %u)",
108 DefaultMaterialLightingConstants::MAX_LIGHT_COUNT);
109 #endif
110 return;
111 }
112 if (renderLight.lightUsageFlags & RenderLight::LIGHT_USAGE_DIRECTIONAL_LIGHT_BIT) {
113 lightCounts_.directional++;
114 } else if (renderLight.lightUsageFlags & RenderLight::LIGHT_USAGE_SPOT_LIGHT_BIT) {
115 lightCounts_.spot++;
116 } else if (renderLight.lightUsageFlags & RenderLight::LIGHT_USAGE_POINT_LIGHT_BIT) {
117 lightCounts_.point++;
118 }
119 if (renderLight.lightUsageFlags & RenderLight::LIGHT_USAGE_SHADOW_LIGHT_BIT) {
120 const uint32_t shadowCount = lightCounts_.dirShadow + lightCounts_.spotShadow;
121 if (shadowCount < DefaultMaterialLightingConstants::MAX_SHADOW_COUNT) {
122 if (renderLight.lightUsageFlags & RenderLight::LIGHT_USAGE_DIRECTIONAL_LIGHT_BIT) {
123 lightCounts_.dirShadow++;
124 } else if (renderLight.lightUsageFlags & RenderLight::LIGHT_USAGE_SPOT_LIGHT_BIT) {
125 lightCounts_.spotShadow++;
126 }
127 renderLight.shadowIndex = shadowCount; // shadow index in atlas
128 lightCounts_.shadowCount = lightCounts_.spotShadow + lightCounts_.dirShadow;
129 }
130 }
131 lights_.push_back(move(renderLight));
132 }
133
GetLights() const134 array_view<const RenderLight> RenderDataStoreDefaultLight::GetLights() const
135 {
136 return array_view<const RenderLight>(lights_);
137 }
138
GetLightCounts() const139 IRenderDataStoreDefaultLight::LightCounts RenderDataStoreDefaultLight::GetLightCounts() const
140 {
141 return lightCounts_;
142 }
143
GetLightingFlags() const144 IRenderDataStoreDefaultLight::LightingFlags RenderDataStoreDefaultLight::GetLightingFlags() const
145 {
146 LightingFlags lightingSpecializationFlags = 0u;
147 if (shadowTypes_.shadowType == IRenderDataStoreDefaultLight::ShadowType::VSM) {
148 lightingSpecializationFlags |= LightingFlagBits::LIGHTING_SHADOW_TYPE_VSM_BIT;
149 }
150 if (lightCounts_.point > 0u) {
151 lightingSpecializationFlags |= LightingFlagBits::LIGHTING_POINT_ENABLED_BIT;
152 }
153 if (lightCounts_.spot > 0u) {
154 lightingSpecializationFlags |= LightingFlagBits::LIGHTING_SPOT_ENABLED_BIT;
155 }
156 return lightingSpecializationFlags;
157 }
158
159 // for plugin / factory interface
Create(RENDER_NS::IRenderContext &,char const * name)160 refcnt_ptr<IRenderDataStore> RenderDataStoreDefaultLight::Create(RENDER_NS::IRenderContext&, char const* name)
161 {
162 return refcnt_ptr<IRenderDataStore>(new RenderDataStoreDefaultLight(name));
163 }
164 CORE3D_END_NAMESPACE()
165