+ if(!current_state || state_stack.size()>1)
+ throw invalid_operation("Renderer::end");
+
+ RendererBackend::end();
+
+ current_state = 0;
+ state_stack.clear();
+ texture_stack.clear();
+ shdata_stack.clear();
+}
+
+void Renderer::push_state()
+{
+ if(state_stack.empty())
+ throw invalid_operation("Renderer::push_state");
+
+ state_stack.push_back(state_stack.back());
+ current_state = &state_stack.back();
+}
+
+void Renderer::pop_state()
+{
+ if(state_stack.size()==1)
+ throw stack_underflow("Renderer::pop_state");
+
+ uintptr_t old_pipeline = current_state->pipeline_key;
+
+ state_stack.pop_back();
+ current_state = &state_stack.back();
+ changed |= MATRIX;
+
+ if(current_state->pipeline_key!=old_pipeline)
+ changed |= PIPELINE_KEY;
+}
+
+Renderer::State &Renderer::get_state() const
+{
+#ifdef DEBUG
+ if(!current_state)
+ throw invalid_operation("Renderer::get_state");
+#endif
+ return *current_state;
+}
+
+void Renderer::set_pipeline_key(uintptr_t key)
+{
+ State &state = get_state();
+ if(key!=state.pipeline_key)
+ {
+ state.pipeline_key = key;
+ changed |= PIPELINE_KEY;
+ }