Skip to content

Commit 222b713

Browse files
Merge pull request #1433 from vsg-dev/viewMaxSlot
Restructured State::stateStack and ViewportState management for flexibility and efficiency.
2 parents bdda068 + b1d8b1f commit 222b713

28 files changed

Lines changed: 421 additions & 112 deletions

include/vsg/app/CommandGraph.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ namespace vsg
3939

4040
int queueFamily = -1;
4141
int presentFamily = -1;
42-
uint32_t maxSlot = 2;
4342
int submitOrder = 0;
43+
Slots maxSlots;
4444

4545
ref_ptr<RecordTraversal> getOrCreateRecordTraversal();
4646

include/vsg/app/CompileManager.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ namespace vsg
2727
{
2828
int result = VK_INCOMPLETE;
2929
std::string message;
30-
uint32_t maxSlot = 0;
30+
Slots maxSlots;
3131
bool containsPagedLOD = false;
3232
ResourceRequirements::Views views;
3333
ResourceRequirements::DynamicData dynamicData;

include/vsg/app/RecordTraversal.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
1616
#include <vsg/core/Object.h>
1717
#include <vsg/core/type_name.h>
1818
#include <vsg/maths/mat4.h>
19+
#include <vsg/vk/Slots.h>
1920

2021
#include <set>
2122
#include <vector>
@@ -69,7 +70,7 @@ namespace vsg
6970
class VSG_DECLSPEC RecordTraversal : public Object
7071
{
7172
public:
72-
explicit RecordTraversal(uint32_t in_maxSlot = 2, const std::set<Bin*>& in_bins = {});
73+
explicit RecordTraversal(const Slots& in_maxSlots = {}, const std::set<Bin*>& in_bins = {});
7374

7475
RecordTraversal(const RecordTraversal&) = delete;
7576
RecordTraversal& operator=(const RecordTraversal& rhs) = delete;

include/vsg/app/RenderGraph.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
1717
#include <vsg/app/Camera.h>
1818
#include <vsg/app/Window.h>
1919
#include <vsg/app/WindowResizeHandler.h>
20+
#include <vsg/state/ResourceHints.h>
2021

2122
namespace vsg
2223
{
@@ -67,6 +68,8 @@ namespace vsg
6768
/// Subpass contents setting passed to vkCmdBeginRenderPass
6869
VkSubpassContents contents = VK_SUBPASS_CONTENTS_INLINE;
6970

71+
uint32_t viewportStateHint = DYNAMIC_VIEWPORTSTATE;
72+
7073
/// Callback used to automatically update viewports, scissors, renderArea and clears when the window is resized.
7174
/// By default resize handling is done.
7275
ref_ptr<WindowResizeHandler> windowResizeHandler;

include/vsg/app/WindowResizeHandler.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ namespace vsg
4444
class VSG_DECLSPEC WindowResizeHandler : public Inherit<Visitor, WindowResizeHandler>
4545
{
4646
public:
47+
ref_ptr<Context> context;
4748
VkRect2D renderArea;
4849
VkExtent2D previous_extent;
4950
VkExtent2D new_extent;
@@ -64,6 +65,7 @@ namespace vsg
6465
/// return true if the object was visited
6566
bool visit(const Object* object, uint32_t index = 0);
6667

68+
void apply(BindGraphicsPipeline& bindPipeline) override;
6769
void apply(Object& object) override;
6870
void apply(ClearAttachments& clearAttachments) override;
6971
void apply(View& view) override;

include/vsg/state/ResourceHints.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,21 @@ namespace vsg
2424
COMPILE_TRAVERSAL_USE_TRANSFER_TASK
2525
};
2626

27+
enum ViewportStateMask : uint32_t
28+
{
29+
STATIC_VIEWPORTSTATE = 1 << 0,
30+
DYNAMIC_VIEWPORTSTATE = 1 << 1
31+
};
32+
2733
/// ResourceHints provides settings that help preallocation of Vulkan resources and memory.
2834
class VSG_DECLSPEC ResourceHints : public Inherit<Object, ResourceHints>
2935
{
3036
public:
3137
ResourceHints();
3238

33-
bool empty() const noexcept { return maxSlot == 0 && numDescriptorSets == 0 && descriptorPoolSizes.empty(); }
39+
bool empty() const noexcept { return maxSlots.state == 0 && maxSlots.view == 0 && numDescriptorSets == 0 && descriptorPoolSizes.empty(); }
3440

35-
uint32_t maxSlot = 0;
41+
Slots maxSlots;
3642
uint32_t numDescriptorSets = 0;
3743
DescriptorPoolSizes descriptorPoolSizes;
3844

@@ -48,6 +54,7 @@ namespace vsg
4854
uint32_t numDatabasePagerReadThreads = 4;
4955

5056
DataTransferHint dataTransferHint = COMPILE_TRAVERSAL_USE_TRANSFER_TASK;
57+
uint32_t viewportStateHint = DYNAMIC_VIEWPORTSTATE;
5158

5259
public:
5360
void read(Input& input) override;

include/vsg/vk/CommandBuffer.h

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ namespace vsg
2222
// forward declare
2323
class ViewDependentState;
2424
class GPUStatsCollection;
25+
class State;
2526

2627
/// CommandBuffer encapsulates VkCommandBuffer
2728
class VSG_DECLSPEC CommandBuffer : public Inherit<Object, CommandBuffer>
@@ -38,6 +39,7 @@ namespace vsg
3839
Mask traversalMask = MASK_ALL;
3940
Mask overrideMask = MASK_OFF;
4041
ViewDependentState* viewDependentState = nullptr;
42+
State* state = nullptr;
4143
ref_ptr<GPUStatsCollection> gpuStats;
4244

4345
VkCommandBufferLevel level() const { return _level; }
@@ -51,14 +53,7 @@ namespace vsg
5153
CommandPool* getCommandPool() { return _commandPool; }
5254
const CommandPool* getCommandPool() const { return _commandPool; }
5355

54-
void setCurrentPipelineLayout(const PipelineLayout* pipelineLayout)
55-
{
56-
_currentPipelineLayout = pipelineLayout->vk(deviceID);
57-
if (pipelineLayout->pushConstantRanges.empty())
58-
_currentPushConstantStageFlags = 0;
59-
else
60-
_currentPushConstantStageFlags = pipelineLayout->pushConstantRanges.front().stageFlags;
61-
}
56+
void setCurrentPipelineLayout(const PipelineLayout* pipelineLayout);
6257

6358
VkPipelineLayout getCurrentPipelineLayout() const { return _currentPipelineLayout; }
6459
VkShaderStageFlags getCurrentPushConstantStageFlags() const { return _currentPushConstantStageFlags; }

include/vsg/vk/ResourceRequirements.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ namespace vsg
8888
Views views;
8989
ViewDetailStack viewDetailsStack;
9090

91-
uint32_t maxSlot = 0;
91+
Slots maxSlots;
9292
uint32_t externalNumDescriptorSets = 0;
9393
bool containsPagedLOD = false;
9494

@@ -102,6 +102,7 @@ namespace vsg
102102
uivec2 shadowMapSize = {2048, 2048};
103103

104104
DataTransferHint dataTransferHint = COMPILE_TRAVERSAL_USE_TRANSFER_TASK;
105+
uint32_t viewportStateHint = DYNAMIC_VIEWPORTSTATE;
105106
};
106107
VSG_type_name(vsg::ResourceRequirements);
107108

include/vsg/vk/Slots.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#pragma once
2+
3+
/* <editor-fold desc="MIT License">
4+
5+
Copyright(c) 2025 Robert Osfield
6+
7+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
8+
9+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
10+
11+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12+
13+
</editor-fold> */
14+
15+
namespace vsg
16+
{
17+
18+
/// max slot values used for general state and view state related State::stateStacks
19+
struct Slots
20+
{
21+
uint32_t state = 0;
22+
uint32_t view = 0;
23+
24+
/// return maximum of the state and view slot numbers
25+
uint32_t max() const
26+
{
27+
return view > state ? view : state;
28+
}
29+
30+
void merge(const Slots& rhs)
31+
{
32+
if (rhs.state > state) state = rhs.state;
33+
if (rhs.view > view) view = rhs.view;
34+
}
35+
};
36+
37+
} // namespace vsg

include/vsg/vk/State.h

Lines changed: 53 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -26,48 +26,51 @@ namespace vsg
2626
{
2727

2828
#define POLYTOPE_SIZE 5
29+
#define STATESTACK_SIZE 16
2930

3031
/// StateStack used internally by vsg::State to manage stack of vsg::StateCommand
3132
template<class T>
3233
class StateStack
3334
{
3435
public:
35-
StateStack() :
36-
dirty(false) {}
36+
StateStack() {}
3737

38-
using Stack = std::stack<ref_ptr<const T>>;
38+
using Stack = std::array<const T*, STATESTACK_SIZE>;
3939
Stack stack;
40-
bool dirty;
40+
size_t pos = 0;
4141

42-
template<class R>
43-
inline void push(ref_ptr<R> value)
42+
inline void reset()
4443
{
45-
stack.push(value);
46-
dirty = true;
44+
pos = 0;
45+
stack[0] = nullptr;
4746
}
4847

49-
template<class R>
50-
inline void push(R* value)
48+
inline void dirty()
5149
{
52-
stack.push(ref_ptr<const T>(value));
53-
dirty = true;
50+
stack[0] = nullptr;
51+
}
52+
53+
inline void push(const T* value)
54+
{
55+
stack[++pos] = value;
5456
}
5557

5658
inline void pop()
5759
{
58-
stack.pop();
59-
dirty = !stack.empty();
60+
--pos;
6061
}
61-
bool empty() const { return stack.empty(); }
62-
size_t size() const { return stack.size(); }
63-
const T* top() const { return stack.top(); }
62+
63+
bool empty() const { return pos == 0; }
64+
size_t size() const { return pos; }
65+
const T* top() const { return stack[pos]; }
6466

6567
inline void record(CommandBuffer& commandBuffer)
6668
{
67-
if (dirty)
69+
const T* current = stack[pos];
70+
if (current != stack[0])
6871
{
69-
stack.top()->record(commandBuffer);
70-
dirty = false;
72+
current->record(commandBuffer);
73+
stack[0] = current;
7174
}
7275
}
7376
};
@@ -228,11 +231,7 @@ namespace vsg
228231
class State : public Inherit<Object, State>
229232
{
230233
public:
231-
explicit State(uint32_t maxSlot) :
232-
dirty(false),
233-
stateStacks(static_cast<size_t>(maxSlot) + 1)
234-
{
235-
}
234+
explicit State(const Slots& in_maxSlots);
236235

237236
using StateCommandStack = StateStack<StateCommand>;
238237
using StateStacks = std::vector<StateCommandStack>;
@@ -252,15 +251,28 @@ namespace vsg
252251
dmat4 inheritedViewMatrix;
253252
dmat4 inheritedViewTransform;
254253

254+
Slots maxSlots;
255+
uint32_t activeMaxStateSlot = 0;
256+
255257
StateStacks stateStacks;
256258

259+
uint32_t viewportStateHint = 0;
260+
257261
MatrixStack projectionMatrixStack{0};
258262
MatrixStack modelviewMatrixStack{64};
259263

260-
void reserve(uint32_t maxSlot)
264+
void reserve(const Slots& in_maxSlots);
265+
266+
void connect(ref_ptr<CommandBuffer> commandBuffer);
267+
268+
void reset();
269+
270+
inline void dirtyStateStacks()
261271
{
262-
size_t required_size = static_cast<size_t>(maxSlot) + 1;
263-
if (required_size > stateStacks.size()) stateStacks.resize(required_size);
272+
for (auto& stateStack : stateStacks)
273+
{
274+
stateStack.dirty();
275+
}
264276
}
265277

266278
void setInhertiedViewProjectionAndViewMatrix(const dmat4& projMatrix, const dmat4& viewMatrix)
@@ -295,11 +307,14 @@ namespace vsg
295307
{
296308
if (dirty)
297309
{
298-
for (auto& stateStack : stateStacks)
310+
for (uint32_t slot = 0; slot <= activeMaxStateSlot; ++slot)
299311
{
300-
stateStack.record(*_commandBuffer);
312+
stateStacks[slot].record(*_commandBuffer);
301313
}
302314

315+
// reset the active maxslot to the minimum required
316+
activeMaxStateSlot = maxSlots.state;
317+
303318
projectionMatrixStack.record(*_commandBuffer);
304319
modelviewMatrixStack.record(*_commandBuffer);
305320

@@ -349,6 +364,14 @@ namespace vsg
349364
dirty = true;
350365
}
351366

367+
void pushView(ref_ptr<StateCommand> command);
368+
369+
void popView(ref_ptr<StateCommand> command);
370+
371+
void pushView(const View& view);
372+
373+
void popView(const View& view);
374+
352375
inline void pushFrustum()
353376
{
354377
_frustumStack.push(Frustum(_frustumProjected, modelviewMatrixStack.top()));

0 commit comments

Comments
 (0)