render command_block

This commit is contained in:
2018-10-25 18:49:32 +07:00
parent 774368a0a4
commit 8d5758c2d7
7 changed files with 452 additions and 104 deletions

View File

@@ -182,7 +182,7 @@ namespace e2d
attribute_type type,
bool normalized) noexcept;
const attribute_info& attribute(std::size_t i) const noexcept;
const attribute_info& attribute(std::size_t index) const noexcept;
std::size_t attribute_count() const noexcept;
std::size_t bytes_per_vertex() const noexcept;
private:
@@ -708,6 +708,118 @@ namespace e2d
topology topology_ = topology::triangles;
u8 _pad[7] = {0};
};
class swap_command final {
public:
swap_command() = default;
swap_command(bool vsync);
swap_command& vsync(bool value) noexcept;
bool& vsync() noexcept;
bool vsync() const noexcept;
private:
bool vsync_ = true;
};
class draw_command final {
public:
draw_command() = delete;
draw_command(const material& mat, const geometry& geo) noexcept;
draw_command& material_ref(const material& value) noexcept;
draw_command& geometry_ref(const geometry& value) noexcept;
const material& material_ref() const noexcept;
const geometry& geometry_ref() const noexcept;
draw_command& properties(const property_block& value);
property_block& properties() noexcept;
const property_block& properties() const noexcept;
private:
const material* material_ = nullptr;
const geometry* geometry_ = nullptr;
property_block properties_;
};
class clear_command final {
public:
enum class buffer : u8 {
color = (1 << 0),
depth = (1 << 1),
stencil = (1 << 2),
color_depth = color | depth,
color_stencil = color | stencil,
depth_stencil = depth | stencil,
color_depth_stencil = color | depth | stencil
};
public:
clear_command() = default;
clear_command(buffer clear_buffer) noexcept;
clear_command& color_value(const color& value) noexcept;
clear_command& depth_value(f32 value) noexcept;
clear_command& stencil_value(u8 value) noexcept;
color& color_value() noexcept;
f32& depth_value() noexcept;
u8& stencil_value() noexcept;
const color& color_value() const noexcept;
f32 depth_value() const noexcept;
u8 stencil_value() const noexcept;
buffer& clear_buffer() noexcept;
buffer clear_buffer() const noexcept;
private:
color color_value_ = color::clear();
f32 depth_value_ = 1.f;
u8 stencil_value_ = 0;
buffer clear_buffer_ = buffer::color_depth_stencil;
u8 _pad[2] = {0};
};
class viewport_command final {
public:
viewport_command() = default;
viewport_command(const b2u& rect) noexcept;
viewport_command& rect(const b2u& value) noexcept;
b2u& rect() noexcept;
const b2u& rect() const noexcept;
private:
b2u rect_;
};
class render_target_command final {
public:
render_target_command() = default;
render_target_command(const render_target_ptr& rt) noexcept;
render_target_command& render_target(const render_target_ptr& value) noexcept;
render_target_ptr& render_target() noexcept;
const render_target_ptr& render_target() const noexcept;
private:
render_target_ptr render_target_;
};
using command_value = stdex::variant<
swap_command,
draw_command,
clear_command,
viewport_command,
render_target_command>;
template < std::size_t N >
class command_block final {
public:
command_block() = default;
command_block& clear() noexcept;
command_block& add_command(command_value&& value);
command_block& add_command(const command_value& value);
const command_value& command(std::size_t index) const noexcept;
std::size_t command_count() const noexcept;
private:
array<command_value, N> commands_;
std::size_t command_count_ = 0;
};
public:
render(debug& d, window& w);
~render() noexcept final;
@@ -746,20 +858,15 @@ namespace e2d
const pixel_declaration& depth_decl,
render_target::external_texture external_texture);
void draw(
const material& mat,
const geometry& geo);
template < std::size_t N >
render& execute(const command_block<N>& commands);
render& execute(const command_value& command);
void draw(
const material& mat,
const geometry& geo,
const property_block& props);
render& clear_depth_buffer(f32 value) noexcept;
render& clear_stencil_buffer(u8 value) noexcept;
render& clear_color_buffer(const color& value) noexcept;
render& set_viewport(const b2u& rect) noexcept;
render& set_render_target(const render_target_ptr& rt) noexcept;
render& execute(const swap_command& command);
render& execute(const draw_command& command);
render& execute(const clear_command& command);
render& execute(const viewport_command& command);
render& execute(const render_target_command& command);
private:
class internal_state;
std::unique_ptr<internal_state> state_;

View File

@@ -106,6 +106,59 @@ namespace e2d
stdex::invoke(f, p.first, p.second);
}
}
//
// render::command_block
//
template < std::size_t N >
render::command_block<N>& render::command_block<N>::clear() noexcept {
commands_.clear();
return *this;
}
template < std::size_t N >
render::command_block<N>& render::command_block<N>::add_command(command_value&& value) {
E2D_ASSERT(command_count_ < commands_.size());
commands_[command_count_] = std::move(value);
++command_count_;
return *this;
}
template < std::size_t N >
render::command_block<N>& render::command_block<N>::add_command(const command_value& value) {
E2D_ASSERT(command_count_ < commands_.size());
commands_[command_count_] = value;
++command_count_;
return *this;
}
template < std::size_t N >
const render::command_value& render::command_block<N>::command(std::size_t index) const noexcept {
E2D_ASSERT(index < command_count_);
return commands_[index];
}
template < std::size_t N >
std::size_t render::command_block<N>::command_count() const noexcept {
return command_count_;
}
//
// render
//
template < std::size_t N >
render& render::execute(const command_block<N>& commands) {
E2D_ASSERT(
std::this_thread::get_id() ==
modules::main_thread<render>());
for ( std::size_t i = 0; i < commands.command_count(); ++i ) {
execute(commands.command(i));
}
return *this;
}
}
#endif

View File

@@ -180,11 +180,10 @@ int e2d_main() {
.property("u_time", game_time)
.property("u_MVP", projection);
the<render>()
.clear_depth_buffer(1.f)
.clear_stencil_buffer(0)
.clear_color_buffer({1.f, 0.4f, 0.f, 1.f})
.draw(material, geometry);
the<render>().execute(render::command_block<64>()
.add_command(render::clear_command()
.color_value({1.f, 0.4f, 0.f, 1.f}))
.add_command(render::draw_command(material, geometry)));
the<window>().swap_buffers(true);
the<input>().frame_tick();

View File

@@ -247,11 +247,10 @@ int e2d_main() {
.property("u_time", game_time)
.property("u_MVP", MVP);
the<render>()
.clear_depth_buffer(1.f)
.clear_stencil_buffer(0)
.clear_color_buffer({1.f, 0.4f, 0.f, 1.f})
.draw(material, geometry);
the<render>().execute(render::command_block<64>()
.add_command(render::clear_command()
.color_value({1.f, 0.4f, 0.f, 1.f}))
.add_command(render::draw_command(material, geometry)));
the<window>().swap_buffers(true);
the<input>().frame_tick();

View File

@@ -205,37 +205,32 @@ int e2d_main() {
.property("u_time", game_time)
.property("u_MVP", MVP);
material.properties()
.sampler("u_texture", render::sampler_state()
.texture(texture)
.min_filter(render::sampler_min_filter::linear)
.mag_filter(render::sampler_mag_filter::linear));
the<render>().execute(render::command_block<64>()
.add_command(render::render_target_command(rt))
.add_command(render::viewport_command(rt->size()))
.add_command(render::clear_command()
.color_value({0.f, 0.4f, 0.f, 1.f}))
.add_command(render::draw_command(material, geometry)
.properties(render::property_block()
.sampler("u_texture", render::sampler_state()
.texture(texture)
.min_filter(render::sampler_min_filter::linear)
.mag_filter(render::sampler_mag_filter::linear))))
.add_command(render::render_target_command(nullptr))
.add_command(render::viewport_command(the<window>().real_size()))
.add_command(render::clear_command()
.color_value({1.f, 0.4f, 0.f, 1.f}))
.add_command(render::draw_command(material, geometry)
.properties(render::property_block()
.sampler("u_texture", render::sampler_state()
.texture(rt->color())
.min_filter(render::sampler_min_filter::linear)
.mag_filter(render::sampler_mag_filter::linear))))
.add_command(render::swap_command(true)));
the<render>()
.set_render_target(rt)
.set_viewport(rt->size())
.clear_depth_buffer(1.f)
.clear_stencil_buffer(0)
.clear_color_buffer({0.f, 0.4f, 0.f, 1.f})
.draw(material, geometry);
std::this_thread::sleep_for(
time::to_chrono(make_milliseconds(10)));
material.properties()
.sampler("u_texture", render::sampler_state()
.texture(rt->color())
.min_filter(render::sampler_min_filter::linear)
.mag_filter(render::sampler_mag_filter::linear));
the<render>()
.set_render_target(nullptr)
.set_viewport(the<window>().real_size())
.clear_depth_buffer(1.f)
.clear_stencil_buffer(0)
.clear_color_buffer({1.f, 0.4f, 0.f, 1.f})
.draw(material, geometry);
std::this_thread::sleep_for(time::to_chrono(make_milliseconds(10)));
the<window>().swap_buffers(true);
the<input>().frame_tick();
window::poll_events();
}

View File

@@ -75,6 +75,34 @@ namespace
}
#undef DEFINE_CASE
}
class command_value_visitor final : private noncopyable {
public:
command_value_visitor(render& render) noexcept
: render_(render) {}
void operator()(const render::swap_command& command) const {
render_.execute(command);
}
void operator()(const render::draw_command& command) const {
render_.execute(command);
}
void operator()(const render::clear_command& command) const {
render_.execute(command);
}
void operator()(const render::viewport_command& command) const {
render_.execute(command);
}
void operator()(const render::render_target_command& command) const {
render_.execute(command);
}
private:
render& render_;
};
}
namespace e2d
@@ -199,9 +227,9 @@ namespace e2d
return *this;
}
const vertex_declaration::attribute_info& vertex_declaration::attribute(std::size_t i) const noexcept {
E2D_ASSERT(i < attribute_count_);
return attributes_[i];
const vertex_declaration::attribute_info& vertex_declaration::attribute(std::size_t index) const noexcept {
E2D_ASSERT(index < attribute_count_);
return attributes_[index];
}
std::size_t vertex_declaration::attribute_count() const noexcept {
@@ -828,4 +856,173 @@ namespace e2d
E2D_ASSERT(index < vertices_count_);
return vertices_[index];
}
//
// swap_command
//
render::swap_command::swap_command(bool vsync)
: vsync_(vsync) {}
render::swap_command& render::swap_command::vsync(bool value) noexcept {
vsync_ = value;
return *this;
}
bool& render::swap_command::vsync() noexcept {
return vsync_;
}
bool render::swap_command::vsync() const noexcept {
return vsync_;
}
//
// draw_command
//
render::draw_command::draw_command(const material& mat, const geometry& geo) noexcept
: material_(&mat)
, geometry_(&geo) {}
render::draw_command& render::draw_command::material_ref(const material& value) noexcept {
material_ = &value;
return *this;
}
render::draw_command& render::draw_command::geometry_ref(const geometry& value) noexcept {
geometry_ = &value;
return *this;
}
const render::material& render::draw_command::material_ref() const noexcept {
E2D_ASSERT(material_);
return *material_;
}
const render::geometry& render::draw_command::geometry_ref() const noexcept {
E2D_ASSERT(geometry_);
return *geometry_;
}
render::draw_command& render::draw_command::properties(const property_block& value) {
properties_ = value;
return *this;
}
render::property_block& render::draw_command::properties() noexcept {
return properties_;
}
const render::property_block& render::draw_command::properties() const noexcept {
return properties_;
}
//
// clear_command
//
render::clear_command::clear_command(buffer clear_buffer) noexcept
: clear_buffer_(clear_buffer) {}
render::clear_command& render::clear_command::color_value(const color& value) noexcept {
color_value_ = value;
return *this;
}
render::clear_command& render::clear_command::depth_value(f32 value) noexcept {
depth_value_ = value;
return *this;
}
render::clear_command& render::clear_command::stencil_value(u8 value) noexcept {
stencil_value_ = value;
return *this;
}
color& render::clear_command::color_value() noexcept {
return color_value_;
}
f32& render::clear_command::depth_value() noexcept {
return depth_value_;
}
u8& render::clear_command::stencil_value() noexcept {
return stencil_value_;
}
const color& render::clear_command::color_value() const noexcept {
return color_value_;
}
f32 render::clear_command::depth_value() const noexcept {
return depth_value_;
}
u8 render::clear_command::stencil_value() const noexcept {
return stencil_value_;
}
render::clear_command::buffer& render::clear_command::clear_buffer() noexcept {
return clear_buffer_;
}
render::clear_command::buffer render::clear_command::clear_buffer() const noexcept {
return clear_buffer_;
}
//
// viewport_command
//
render::viewport_command::viewport_command(const b2u& rect) noexcept
: rect_(rect) {}
render::viewport_command& render::viewport_command::rect(const b2u& value) noexcept {
rect_ = value;
return *this;
}
b2u& render::viewport_command::rect() noexcept {
return rect_;
}
const b2u& render::viewport_command::rect() const noexcept {
return rect_;
}
//
// render_target_command
//
render::render_target_command::render_target_command(const render_target_ptr& rt) noexcept
: render_target_(rt) {}
render::render_target_command& render::render_target_command::render_target(const render_target_ptr& value) noexcept {
render_target_ = value;
return *this;
}
render_target_ptr& render::render_target_command::render_target() noexcept {
return render_target_;
}
const render_target_ptr& render::render_target_command::render_target() const noexcept {
return render_target_;
}
//
// render
//
render& render::execute(const command_value& command) {
E2D_ASSERT(
std::this_thread::get_id() ==
modules::main_thread<render>());
E2D_ASSERT(!command.valueless_by_exception());
stdex::visit(command_value_visitor(*this), command);
return *this;
}
}

View File

@@ -17,7 +17,7 @@ namespace
class property_block_value_visitor : private noncopyable {
public:
property_block_value_visitor(debug& debug, uniform_info ui)
property_block_value_visitor(debug& debug, uniform_info ui) noexcept
: debug_(debug)
, ui_(std::move(ui)) {}
@@ -768,26 +768,24 @@ namespace e2d
std::move(depth_rb)));
}
void render::draw(
const material& mat,
const geometry& geo)
{
render& render::execute(const swap_command& command) {
E2D_ASSERT(
std::this_thread::get_id() ==
modules::main_thread<render>());
draw(mat, geo, property_block());
state_->wnd().swap_buffers(command.vsync());
return *this;
}
void render::draw(
const material& mat,
const geometry& geo,
const property_block& props)
{
render& render::execute(const draw_command& command) {
E2D_ASSERT(
std::this_thread::get_id() ==
modules::main_thread<render>());
const material& mat = command.material_ref();
const geometry& geo = command.geometry_ref();
const property_block& props = command.properties();
for ( std::size_t i = 0; i < mat.pass_count(); ++i ) {
const pass_state& pass = mat.pass(i);
const property_block& main_props = main_property_cache()
@@ -802,59 +800,59 @@ namespace e2d
});
});
}
}
render& render::clear_depth_buffer(f32 value) noexcept {
E2D_ASSERT(
std::this_thread::get_id() ==
modules::main_thread<render>());
const render_target_ptr& rt = state_->render_target();
if ( !rt || rt->state().depth() || !rt->state().depth_rb().empty() ) {
GL_CHECK_CODE(state_->dbg(), glClearDepth(
math::numeric_cast<GLclampd>(math::saturate(value))));
GL_CHECK_CODE(state_->dbg(), glClear(GL_DEPTH_BUFFER_BIT));
}
return *this;
}
render& render::clear_stencil_buffer(u8 value) noexcept {
render& render::execute(const clear_command& command) {
E2D_ASSERT(
std::this_thread::get_id() ==
modules::main_thread<render>());
const render_target_ptr& rt = state_->render_target();
if ( !rt || rt->state().depth() || !rt->state().depth_rb().empty() ) {
GL_CHECK_CODE(state_->dbg(), glClearStencil(
math::numeric_cast<GLint>(value)));
GL_CHECK_CODE(state_->dbg(), glClear(GL_STENCIL_BUFFER_BIT));
}
return *this;
}
render& render::clear_color_buffer(const color& value) noexcept {
E2D_ASSERT(
std::this_thread::get_id() ==
modules::main_thread<render>());
bool clear_color =
math::enum_to_number(command.clear_buffer())
& math::enum_to_number(clear_command::buffer::color);
bool clear_depth =
math::enum_to_number(command.clear_buffer())
& math::enum_to_number(clear_command::buffer::depth);
bool clear_stencil =
math::enum_to_number(command.clear_buffer())
& math::enum_to_number(clear_command::buffer::stencil);
const render_target_ptr& rt = state_->render_target();
if ( !rt || rt->state().color() || !rt->state().color_rb().empty() ) {
bool has_color = !rt || rt->state().color() || !rt->state().color_rb().empty();
bool has_depth = !rt || rt->state().depth() || !rt->state().depth_rb().empty();
GLbitfield clear_mask = 0;
if ( has_color && clear_color ) {
clear_mask |= GL_COLOR_BUFFER_BIT;
GL_CHECK_CODE(state_->dbg(), glClearColor(
math::numeric_cast<GLclampf>(math::saturate(value.r)),
math::numeric_cast<GLclampf>(math::saturate(value.g)),
math::numeric_cast<GLclampf>(math::saturate(value.b)),
math::numeric_cast<GLclampf>(math::saturate(value.a))));
GL_CHECK_CODE(state_->dbg(), glClear(GL_COLOR_BUFFER_BIT));
math::numeric_cast<GLclampf>(math::saturate(command.color_value().r)),
math::numeric_cast<GLclampf>(math::saturate(command.color_value().g)),
math::numeric_cast<GLclampf>(math::saturate(command.color_value().b)),
math::numeric_cast<GLclampf>(math::saturate(command.color_value().a))));
}
if ( has_depth ) {
if ( clear_depth ) {
clear_mask |= GL_DEPTH_BUFFER_BIT;
GL_CHECK_CODE(state_->dbg(), glClearDepth(
math::numeric_cast<GLclampd>(math::saturate(command.depth_value()))));
}
if ( clear_stencil ) {
clear_mask |= GL_STENCIL_BUFFER_BIT;
GL_CHECK_CODE(state_->dbg(), glClearStencil(
math::numeric_cast<GLint>(command.stencil_value())));
}
}
GL_CHECK_CODE(state_->dbg(), glClear(clear_mask));
return *this;
}
render& render::set_viewport(const b2u& rect) noexcept {
render& render::execute(const viewport_command& command) {
E2D_ASSERT(
std::this_thread::get_id() ==
modules::main_thread<render>());
const b2u vp = make_minmax_rect(rect);
const b2u vp = make_minmax_rect(command.rect());
GL_CHECK_CODE(state_->dbg(), glViewport(
math::numeric_cast<GLint>(vp.position.x),
math::numeric_cast<GLint>(vp.position.y),
@@ -863,12 +861,12 @@ namespace e2d
return *this;
}
render& render::set_render_target(const render_target_ptr& rt) noexcept {
render& render::execute(const render_target_command& command) {
E2D_ASSERT(
std::this_thread::get_id() ==
modules::main_thread<render>());
state_->set_render_target(rt);
state_->set_render_target(command.render_target());
return *this;
}
}