|
|
@ -2,6 +2,10 @@
|
|
|
|
// Licensed under GPLv2 or any later version
|
|
|
|
// Licensed under GPLv2 or any later version
|
|
|
|
// Refer to the license.txt file included.
|
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <boost/serialization/base_object.hpp>
|
|
|
|
|
|
|
|
#include <boost/serialization/export.hpp>
|
|
|
|
|
|
|
|
#include <boost/serialization/unique_ptr.hpp>
|
|
|
|
|
|
|
|
#include "common/archives.h"
|
|
|
|
#include "video_core/geometry_pipeline.h"
|
|
|
|
#include "video_core/geometry_pipeline.h"
|
|
|
|
#include "video_core/pica_state.h"
|
|
|
|
#include "video_core/pica_state.h"
|
|
|
|
#include "video_core/regs.h"
|
|
|
|
#include "video_core/regs.h"
|
|
|
@ -30,6 +34,13 @@ public:
|
|
|
|
* @return if the buffer is full and the geometry shader should be invoked
|
|
|
|
* @return if the buffer is full and the geometry shader should be invoked
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
virtual bool SubmitVertex(const Shader::AttributeBuffer& input) = 0;
|
|
|
|
virtual bool SubmitVertex(const Shader::AttributeBuffer& input) = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
template <class Archive>
|
|
|
|
|
|
|
|
void serialize(Archive& ar, const unsigned int file_version)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
friend class boost::serialization::access;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// In the Point mode, vertex attributes are sent to the input registers in the geometry shader unit.
|
|
|
|
// In the Point mode, vertex attributes are sent to the input registers in the geometry shader unit.
|
|
|
@ -40,7 +51,7 @@ public:
|
|
|
|
// TODO: what happens when the input size is not divisible by the output size?
|
|
|
|
// TODO: what happens when the input size is not divisible by the output size?
|
|
|
|
class GeometryPipeline_Point : public GeometryPipelineBackend {
|
|
|
|
class GeometryPipeline_Point : public GeometryPipelineBackend {
|
|
|
|
public:
|
|
|
|
public:
|
|
|
|
GeometryPipeline_Point(const Regs& regs, Shader::GSUnitState& unit) : regs(regs), unit(unit) {
|
|
|
|
GeometryPipeline_Point() : regs(g_state.regs), unit(g_state.gs_unit) {
|
|
|
|
ASSERT(regs.pipeline.variable_primitive == 0);
|
|
|
|
ASSERT(regs.pipeline.variable_primitive == 0);
|
|
|
|
ASSERT(regs.gs.input_to_uniform == 0);
|
|
|
|
ASSERT(regs.gs.input_to_uniform == 0);
|
|
|
|
vs_output_num = regs.pipeline.vs_outmap_total_minus_1_a + 1;
|
|
|
|
vs_output_num = regs.pipeline.vs_outmap_total_minus_1_a + 1;
|
|
|
@ -79,6 +90,39 @@ private:
|
|
|
|
Common::Vec4<float24>* buffer_cur;
|
|
|
|
Common::Vec4<float24>* buffer_cur;
|
|
|
|
Common::Vec4<float24>* buffer_end;
|
|
|
|
Common::Vec4<float24>* buffer_end;
|
|
|
|
unsigned int vs_output_num;
|
|
|
|
unsigned int vs_output_num;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template <typename Class, class Archive>
|
|
|
|
|
|
|
|
static void serialize_common(Class* self, Archive& ar, const unsigned int version)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
ar & boost::serialization::base_object<GeometryPipelineBackend>(*self);
|
|
|
|
|
|
|
|
ar & self->attribute_buffer;
|
|
|
|
|
|
|
|
ar & self->vs_output_num;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template<class Archive>
|
|
|
|
|
|
|
|
void save(Archive & ar, const unsigned int version) const
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
serialize_common(this, ar, version);
|
|
|
|
|
|
|
|
auto buffer_idx = static_cast<u32>(buffer_cur - attribute_buffer.attr);
|
|
|
|
|
|
|
|
auto buffer_size = static_cast<u32>(buffer_end - attribute_buffer.attr);
|
|
|
|
|
|
|
|
ar << buffer_idx;
|
|
|
|
|
|
|
|
ar << buffer_size;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template<class Archive>
|
|
|
|
|
|
|
|
void load(Archive & ar, const unsigned int version)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
serialize_common(this, ar, version);
|
|
|
|
|
|
|
|
u32 buffer_idx, buffer_size;
|
|
|
|
|
|
|
|
ar >> buffer_idx;
|
|
|
|
|
|
|
|
ar >> buffer_size;
|
|
|
|
|
|
|
|
buffer_cur = attribute_buffer.attr + buffer_idx;
|
|
|
|
|
|
|
|
buffer_end = attribute_buffer.attr + buffer_size;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BOOST_SERIALIZATION_SPLIT_MEMBER()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
friend class boost::serialization::access;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// In VariablePrimitive mode, vertex attributes are buffered into the uniform registers in the
|
|
|
|
// In VariablePrimitive mode, vertex attributes are buffered into the uniform registers in the
|
|
|
@ -86,8 +130,8 @@ private:
|
|
|
|
// value in the batch. This mode is usually used for subdivision.
|
|
|
|
// value in the batch. This mode is usually used for subdivision.
|
|
|
|
class GeometryPipeline_VariablePrimitive : public GeometryPipelineBackend {
|
|
|
|
class GeometryPipeline_VariablePrimitive : public GeometryPipelineBackend {
|
|
|
|
public:
|
|
|
|
public:
|
|
|
|
GeometryPipeline_VariablePrimitive(const Regs& regs, Shader::ShaderSetup& setup)
|
|
|
|
GeometryPipeline_VariablePrimitive()
|
|
|
|
: regs(regs), setup(setup) {
|
|
|
|
: regs(g_state.regs), setup(g_state.gs) {
|
|
|
|
ASSERT(regs.pipeline.variable_primitive == 1);
|
|
|
|
ASSERT(regs.pipeline.variable_primitive == 1);
|
|
|
|
ASSERT(regs.gs.input_to_uniform == 1);
|
|
|
|
ASSERT(regs.gs.input_to_uniform == 1);
|
|
|
|
vs_output_num = regs.pipeline.vs_outmap_total_minus_1_a + 1;
|
|
|
|
vs_output_num = regs.pipeline.vs_outmap_total_minus_1_a + 1;
|
|
|
@ -144,6 +188,37 @@ private:
|
|
|
|
unsigned int total_vertex_num;
|
|
|
|
unsigned int total_vertex_num;
|
|
|
|
Common::Vec4<float24>* buffer_cur;
|
|
|
|
Common::Vec4<float24>* buffer_cur;
|
|
|
|
unsigned int vs_output_num;
|
|
|
|
unsigned int vs_output_num;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template <typename Class, class Archive>
|
|
|
|
|
|
|
|
static void serialize_common(Class* self, Archive& ar, const unsigned int version)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
ar & boost::serialization::base_object<GeometryPipelineBackend>(*self);
|
|
|
|
|
|
|
|
ar & self->need_index;
|
|
|
|
|
|
|
|
ar & self->main_vertex_num;
|
|
|
|
|
|
|
|
ar & self->total_vertex_num;
|
|
|
|
|
|
|
|
ar & self->vs_output_num;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template<class Archive>
|
|
|
|
|
|
|
|
void save(Archive & ar, const unsigned int version) const
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
serialize_common(this, ar, version);
|
|
|
|
|
|
|
|
auto buffer_idx = static_cast<u32>(buffer_cur - setup.uniforms.f);
|
|
|
|
|
|
|
|
ar << buffer_idx;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template<class Archive>
|
|
|
|
|
|
|
|
void load(Archive & ar, const unsigned int version)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
serialize_common(this, ar, version);
|
|
|
|
|
|
|
|
u32 buffer_idx;
|
|
|
|
|
|
|
|
ar >> buffer_idx;
|
|
|
|
|
|
|
|
buffer_cur = setup.uniforms.f + buffer_idx;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BOOST_SERIALIZATION_SPLIT_MEMBER()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
friend class boost::serialization::access;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// In FixedPrimitive mode, vertex attributes are buffered into the uniform registers in the geometry
|
|
|
|
// In FixedPrimitive mode, vertex attributes are buffered into the uniform registers in the geometry
|
|
|
@ -151,8 +226,8 @@ private:
|
|
|
|
// particle system.
|
|
|
|
// particle system.
|
|
|
|
class GeometryPipeline_FixedPrimitive : public GeometryPipelineBackend {
|
|
|
|
class GeometryPipeline_FixedPrimitive : public GeometryPipelineBackend {
|
|
|
|
public:
|
|
|
|
public:
|
|
|
|
GeometryPipeline_FixedPrimitive(const Regs& regs, Shader::ShaderSetup& setup)
|
|
|
|
GeometryPipeline_FixedPrimitive()
|
|
|
|
: regs(regs), setup(setup) {
|
|
|
|
: regs(g_state.regs), setup(g_state.gs) {
|
|
|
|
ASSERT(regs.pipeline.variable_primitive == 0);
|
|
|
|
ASSERT(regs.pipeline.variable_primitive == 0);
|
|
|
|
ASSERT(regs.gs.input_to_uniform == 1);
|
|
|
|
ASSERT(regs.gs.input_to_uniform == 1);
|
|
|
|
vs_output_num = regs.pipeline.vs_outmap_total_minus_1_a + 1;
|
|
|
|
vs_output_num = regs.pipeline.vs_outmap_total_minus_1_a + 1;
|
|
|
@ -190,6 +265,42 @@ private:
|
|
|
|
Common::Vec4<float24>* buffer_cur;
|
|
|
|
Common::Vec4<float24>* buffer_cur;
|
|
|
|
Common::Vec4<float24>* buffer_end;
|
|
|
|
Common::Vec4<float24>* buffer_end;
|
|
|
|
unsigned int vs_output_num;
|
|
|
|
unsigned int vs_output_num;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template <typename Class, class Archive>
|
|
|
|
|
|
|
|
static void serialize_common(Class* self, Archive& ar, const unsigned int version)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
ar & boost::serialization::base_object<GeometryPipelineBackend>(*self);
|
|
|
|
|
|
|
|
ar & self->vs_output_num;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template<class Archive>
|
|
|
|
|
|
|
|
void save(Archive & ar, const unsigned int version) const
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
serialize_common(this, ar, version);
|
|
|
|
|
|
|
|
auto buffer_offset = static_cast<u32>(buffer_begin - setup.uniforms.f);
|
|
|
|
|
|
|
|
auto buffer_idx = static_cast<u32>(buffer_cur - setup.uniforms.f);
|
|
|
|
|
|
|
|
auto buffer_size = static_cast<u32>(buffer_end - setup.uniforms.f);
|
|
|
|
|
|
|
|
ar << buffer_offset;
|
|
|
|
|
|
|
|
ar << buffer_idx;
|
|
|
|
|
|
|
|
ar << buffer_size;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template<class Archive>
|
|
|
|
|
|
|
|
void load(Archive & ar, const unsigned int version)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
serialize_common(this, ar, version);
|
|
|
|
|
|
|
|
u32 buffer_offset, buffer_idx, buffer_size;
|
|
|
|
|
|
|
|
ar >> buffer_offset;
|
|
|
|
|
|
|
|
ar >> buffer_idx;
|
|
|
|
|
|
|
|
ar >> buffer_size;
|
|
|
|
|
|
|
|
buffer_begin = setup.uniforms.f + buffer_offset;
|
|
|
|
|
|
|
|
buffer_cur = setup.uniforms.f + buffer_idx;
|
|
|
|
|
|
|
|
buffer_end = setup.uniforms.f + buffer_size;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BOOST_SERIALIZATION_SPLIT_MEMBER()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
friend class boost::serialization::access;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
GeometryPipeline::GeometryPipeline(State& state) : state(state) {}
|
|
|
|
GeometryPipeline::GeometryPipeline(State& state) : state(state) {}
|
|
|
@ -231,13 +342,13 @@ void GeometryPipeline::Reconfigure() {
|
|
|
|
|
|
|
|
|
|
|
|
switch (state.regs.pipeline.gs_config.mode) {
|
|
|
|
switch (state.regs.pipeline.gs_config.mode) {
|
|
|
|
case PipelineRegs::GSMode::Point:
|
|
|
|
case PipelineRegs::GSMode::Point:
|
|
|
|
backend = std::make_unique<GeometryPipeline_Point>(state.regs, state.gs_unit);
|
|
|
|
backend = std::make_unique<GeometryPipeline_Point>();
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
case PipelineRegs::GSMode::VariablePrimitive:
|
|
|
|
case PipelineRegs::GSMode::VariablePrimitive:
|
|
|
|
backend = std::make_unique<GeometryPipeline_VariablePrimitive>(state.regs, state.gs);
|
|
|
|
backend = std::make_unique<GeometryPipeline_VariablePrimitive>();
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
case PipelineRegs::GSMode::FixedPrimitive:
|
|
|
|
case PipelineRegs::GSMode::FixedPrimitive:
|
|
|
|
backend = std::make_unique<GeometryPipeline_FixedPrimitive>(state.regs, state.gs);
|
|
|
|
backend = std::make_unique<GeometryPipeline_FixedPrimitive>();
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
|
|
|
UNREACHABLE();
|
|
|
@ -271,4 +382,16 @@ void GeometryPipeline::SubmitVertex(const Shader::AttributeBuffer& input) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template <class Archive>
|
|
|
|
|
|
|
|
void GeometryPipeline::serialize(Archive& ar, const unsigned int version) {
|
|
|
|
|
|
|
|
// vertex_handler and shader_engine are always set to the same value
|
|
|
|
|
|
|
|
ar & backend;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} // namespace Pica
|
|
|
|
} // namespace Pica
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BOOST_SERIALIZATION_ASSUME_ABSTRACT(Pica::GeometryPipelineBackend)
|
|
|
|
|
|
|
|
SERIALIZE_EXPORT_IMPL(Pica::GeometryPipeline_Point)
|
|
|
|
|
|
|
|
SERIALIZE_EXPORT_IMPL(Pica::GeometryPipeline_VariablePrimitive)
|
|
|
|
|
|
|
|
SERIALIZE_EXPORT_IMPL(Pica::GeometryPipeline_FixedPrimitive)
|
|
|
|
|
|
|
|
SERIALIZE_IMPL(Pica::GeometryPipeline)
|
|
|
|