99
1010namespace candlewick {
1111
12- DepthPassInfo DepthPassInfo::create (const Renderer &renderer,
13- const MeshLayout &layout,
14- SDL_GPUTexture *depth_texture,
15- const Config &config) {
16- if (depth_texture == nullptr )
17- depth_texture = renderer.depth_texture ;
18- const Device &device = renderer.device ;
12+ DepthPass::DepthPass (const Device &device, const MeshLayout &layout,
13+ SDL_GPUTexture *depth_texture, SDL_GPUTextureFormat format,
14+ const Config &config)
15+ : _device(device), depthTexture(depth_texture) {
1916 auto vertexShader = Shader::fromMetadata (device, " ShadowCast.vert" );
2017 auto fragmentShader = Shader::fromMetadata (device, " ShadowCast.frag" );
2118 SDL_GPUGraphicsPipelineCreateInfo pipeline_desc{
@@ -35,34 +32,88 @@ DepthPassInfo DepthPassInfo::create(const Renderer &renderer,
3532 .enable_depth_write = true },
3633 .target_info {.color_target_descriptions = nullptr ,
3734 .num_color_targets = 0 ,
38- .depth_stencil_format = renderer. depthFormat () ,
35+ .depth_stencil_format = format ,
3936 .has_depth_stencil_target = true },
4037 };
41- return DepthPassInfo{
42- .depthTexture = depth_texture,
43- .pipeline = SDL_CreateGPUGraphicsPipeline (device, &pipeline_desc),
44- ._device = device,
38+ pipeline = SDL_CreateGPUGraphicsPipeline (device, &pipeline_desc);
39+ if (!pipeline)
40+ terminate_with_message (
41+ std::format (" Failed to create graphics pipeline: %s." , SDL_GetError ()));
42+ }
43+
44+ DepthPass::DepthPass (const Device &device, const MeshLayout &layout,
45+ const Texture &texture, const Config &config)
46+ : DepthPass(device, layout, texture, texture.format(), config) {}
47+
48+ DepthPass::DepthPass (DepthPass &&other) noexcept
49+ : _device(other._device)
50+ , depthTexture(other.depthTexture)
51+ , pipeline(other.pipeline) {
52+ other._device = nullptr ;
53+ other.depthTexture = nullptr ;
54+ other.pipeline = nullptr ;
55+ }
56+
57+ DepthPass &DepthPass::operator =(DepthPass &&other) noexcept {
58+ if (this != &other) {
59+ _device = other._device ;
60+ depthTexture = other.depthTexture ;
61+ pipeline = other.pipeline ;
62+ other._device = nullptr ;
63+ other.depthTexture = nullptr ;
64+ other.pipeline = nullptr ;
65+ }
66+ return *this ;
67+ }
68+
69+ void DepthPass::render (CommandBuffer &command_buffer, const Mat4f &viewProj,
70+ std::span<const OpaqueCastable> castables) {
71+ SDL_GPUDepthStencilTargetInfo depth_info{
72+ .texture = depthTexture,
73+ .clear_depth = 1 .0f ,
74+ .load_op = SDL_GPU_LOADOP_CLEAR,
75+ .store_op = SDL_GPU_STOREOP_STORE,
76+ .stencil_load_op = SDL_GPU_LOADOP_DONT_CARE,
77+ .stencil_store_op = SDL_GPU_STOREOP_DONT_CARE,
4578 };
79+
80+ SDL_GPURenderPass *render_pass =
81+ SDL_BeginGPURenderPass (command_buffer, nullptr , 0 , &depth_info);
82+ SDL_BindGPUGraphicsPipeline (render_pass, pipeline);
83+
84+ for (auto &[mesh, tr] : castables) {
85+ assert (validateMesh (mesh));
86+ rend::bindMesh (render_pass, mesh);
87+
88+ Mat4f mvp = viewProj * tr;
89+ command_buffer.pushVertexUniform (DepthPass::TRANSFORM_SLOT, mvp);
90+ rend::draw (render_pass, mesh);
91+ }
92+
93+ SDL_EndGPURenderPass (render_pass);
4694}
4795
48- void DepthPassInfo::release () {
49- // do not release depth texture here, because it is assumed to be borrowed.
50- if (_device && pipeline) {
51- SDL_ReleaseGPUGraphicsPipeline (_device, pipeline);
96+ void DepthPass::release () noexcept {
97+ if (_device) {
98+ if (pipeline) {
99+ SDL_ReleaseGPUGraphicsPipeline (_device, pipeline);
100+ pipeline = nullptr ;
101+ }
102+ if (depthTexture)
103+ depthTexture = nullptr ;
52104 }
53- pipeline = nullptr ;
105+ _device = nullptr ;
54106}
55107
56- ShadowPassInfo ShadowPassInfo::create (const Renderer &renderer,
57- const MeshLayout &layout,
58- const Config &config) {
59- const Device &device = renderer.device ;
108+ ShadowMapPass::ShadowMapPass (const Device &device, const MeshLayout &layout,
109+ SDL_GPUTextureFormat format, const Config &config)
110+ : _device(device) {
60111
61112 // TEXTURE
62113 // 2k x 2k texture
63114 SDL_GPUTextureCreateInfo texInfo{
64115 .type = SDL_GPU_TEXTURETYPE_2D,
65- .format = renderer. depthFormat () ,
116+ .format = format ,
66117 .usage = SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET |
67118 SDL_GPU_TEXTUREUSAGE_SAMPLER,
68119 .width = config.width ,
@@ -73,27 +124,8 @@ ShadowPassInfo ShadowPassInfo::create(const Renderer &renderer,
73124 .props = 0 ,
74125 };
75126
76- SDL_GPUTexture *shadowMap = SDL_CreateGPUTexture (device, &texInfo);
77- SDL_SetGPUTextureName (device, shadowMap, " Shadow map" );
78- if (!shadowMap) {
79- terminate_with_message (
80- std::format (" Failed to create shadow map texture: %s" , SDL_GetError ()));
81- }
82-
83- DepthPassInfo passInfo =
84- DepthPassInfo::create (renderer, layout, shadowMap,
85- {
86- .cull_mode = SDL_GPU_CULLMODE_NONE,
87- .depth_bias_constant_factor = 0 .f ,
88- .depth_bias_slope_factor = 0 .f ,
89- .enable_depth_bias = false ,
90- .enable_depth_clip = false ,
91- });
92- if (!passInfo.pipeline ) {
93- SDL_ReleaseGPUTexture (device, shadowMap);
94- terminate_with_message (std::format (
95- " Failed to create shadow map pipeline: %s" , SDL_GetError ()));
96- }
127+ shadowMap = Texture (device, texInfo, " Shadow map" );
128+ _depthPass = DepthPass (device, layout, shadowMap, config.depthPassConfig );
97129
98130 SDL_GPUSamplerCreateInfo sample_desc{
99131 .min_filter = SDL_GPU_FILTER_LINEAR,
@@ -105,56 +137,42 @@ ShadowPassInfo ShadowPassInfo::create(const Renderer &renderer,
105137 .compare_op = SDL_GPU_COMPAREOP_LESS,
106138 .enable_compare = true ,
107139 };
108- return ShadowPassInfo{passInfo, SDL_CreateGPUSampler (device, &sample_desc)} ;
140+ sampler = SDL_CreateGPUSampler (device, &sample_desc);
109141}
110142
111- void ShadowPassInfo::release () {
112- DepthPassInfo::release ();
113- if (depthTexture) {
114- SDL_ReleaseGPUTexture (_device, depthTexture);
115- }
116- depthTexture = nullptr ;
117- if (sampler) {
118- SDL_ReleaseGPUSampler (_device, sampler);
119- }
120- sampler = nullptr ;
143+ ShadowMapPass::ShadowMapPass (ShadowMapPass &&other) noexcept
144+ : _device(other._device)
145+ , _depthPass(std::move(other._depthPass))
146+ , shadowMap(std::move(other.shadowMap))
147+ , sampler(other.sampler) {
148+ other._device = nullptr ;
149+ other.sampler = nullptr ;
121150}
122151
123- void renderDepthOnlyPass (CommandBuffer &cmdBuf, const DepthPassInfo &passInfo,
124- const Mat4f &viewProj,
125- std::span<const OpaqueCastable> castables) {
126- SDL_GPUDepthStencilTargetInfo depth_info;
127- SDL_zero (depth_info);
128- depth_info.load_op = SDL_GPU_LOADOP_CLEAR;
129- depth_info.store_op = SDL_GPU_STOREOP_STORE;
130- depth_info.stencil_load_op = SDL_GPU_LOADOP_DONT_CARE;
131- depth_info.stencil_store_op = SDL_GPU_STOREOP_DONT_CARE;
132- depth_info.clear_depth = 1 .0f ;
133- // depth texture may be the renderer shared depth texture,
134- // or a specially created texture.
135- depth_info.texture = passInfo.depthTexture ;
136-
137- SDL_GPURenderPass *render_pass =
138- SDL_BeginGPURenderPass (cmdBuf, nullptr , 0 , &depth_info);
152+ ShadowMapPass &ShadowMapPass::operator =(ShadowMapPass &&other) noexcept {
153+ _device = other._device ;
154+ _depthPass = std::move (other._depthPass );
155+ shadowMap = std::move (other.shadowMap );
156+ sampler = other.sampler ;
139157
140- assert (passInfo.pipeline );
141- SDL_BindGPUGraphicsPipeline (render_pass, passInfo.pipeline );
158+ other._device = nullptr ;
159+ other.sampler = nullptr ;
160+ return *this ;
161+ }
142162
143- Mat4f mvp;
144- for (auto &cs : castables) {
145- auto &&[mesh, tr] = cs;
146- assert (validateMesh (mesh));
147- rend::bindMesh (render_pass, mesh);
148- mvp.noalias () = viewProj * tr;
149- cmdBuf.pushVertexUniform (DepthPassInfo::TRANSFORM_SLOT, mvp);
150- rend::draw (render_pass, mesh);
163+ void ShadowMapPass::release () noexcept {
164+ _depthPass.release ();
165+ if (_device) {
166+ if (sampler) {
167+ SDL_ReleaseGPUSampler (_device, sampler);
168+ }
169+ sampler = nullptr ;
151170 }
152-
153- SDL_EndGPURenderPass (render_pass) ;
171+ shadowMap. destroy ();
172+ _device = nullptr ;
154173}
155174
156- void renderShadowPassFromFrustum (CommandBuffer &cmdBuf,
157- ShadowPassInfo &passInfo,
175+ void renderShadowPassFromFrustum (CommandBuffer &cmdBuf, ShadowMapPass &passInfo,
158176 const DirectionalLight &dirLight,
159177 std::span<const OpaqueCastable> castables,
160178 const FrustumCornersType &worldSpaceCorners) {
@@ -175,29 +193,30 @@ void renderShadowPassFromFrustum(CommandBuffer &cmdBuf,
175193 shadowOrthographicMatrix ({bounds.width (), bounds.height ()},
176194 float (bounds.min_ .z ()), float (bounds.max_ .z ()));
177195
178- Mat4f viewProj = passInfo. cam . viewProj () ;
179- renderDepthOnlyPass (cmdBuf, passInfo , viewProj, castables);
196+ Mat4f viewProj = lightView * lightProj ;
197+ passInfo. render (cmdBuf, viewProj, castables);
180198}
181199
182- void renderShadowPassFromAABB (CommandBuffer &cmdBuf, ShadowPassInfo &passInfo,
200+ void renderShadowPassFromAABB (CommandBuffer &cmdBuf, ShadowMapPass &passInfo,
183201 const DirectionalLight &dirLight,
184202 std::span<const OpaqueCastable> castables,
185203 const AABB &worldSceneBounds) {
204+ using Eigen::Vector3d;
205+
186206 Float3 center = worldSceneBounds.center ().cast <float >();
187207 float radius = 0 .5f * float (worldSceneBounds.size ());
188208 radius = std::ceil (radius * 16 .f ) / 16 .f ;
189209 Float3 eye = center - radius * dirLight.direction .normalized ();
190210 auto &lightView = passInfo.cam .view ;
191211 auto &lightProj = passInfo.cam .projection ;
192212 lightView = lookAt (eye, center, Float3::UnitZ ());
193- using Eigen::Vector3d;
194213
195214 AABB bounds{Vector3d::Constant (-radius), Vector3d::Constant (radius)};
196215 lightProj =
197216 shadowOrthographicMatrix ({bounds.width (), bounds.height ()},
198217 float (bounds.min_ .z ()), float (bounds.max_ .z ()));
199218
200219 Mat4f viewProj = lightProj * lightView.matrix ();
201- renderDepthOnlyPass (cmdBuf, passInfo , viewProj, castables);
220+ passInfo. render (cmdBuf, viewProj, castables);
202221}
203222} // namespace candlewick
0 commit comments