render calls on the main thread only

This commit is contained in:
2018-10-23 17:00:43 +07:00
parent 6e333dd191
commit 532663a958
4 changed files with 113 additions and 24 deletions

View File

@@ -21,6 +21,8 @@ namespace e2d
class texture; class texture;
class index_buffer; class index_buffer;
class vertex_buffer; class vertex_buffer;
class render_target;
class pixel_declaration;
class index_declaration; class index_declaration;
class vertex_declaration; class vertex_declaration;
class vfs; class vfs;

View File

@@ -712,8 +712,12 @@ namespace e2d
~render() noexcept final; ~render() noexcept final;
shader_ptr create_shader( shader_ptr create_shader(
input_stream_uptr vertex_stream, const str& vertex_source,
input_stream_uptr fragment_stream); const str& fragment_source);
shader_ptr create_shader(
const input_stream_uptr& vertex_stream,
const input_stream_uptr& fragment_stream);
texture_ptr create_texture( texture_ptr create_texture(
const image& image); const image& image);
@@ -753,7 +757,7 @@ namespace e2d
render& clear_depth_buffer(f32 value) noexcept; render& clear_depth_buffer(f32 value) noexcept;
render& clear_stencil_buffer(u8 value) noexcept; render& clear_stencil_buffer(u8 value) noexcept;
render& clear_color_buffer(const color& value) noexcept; render& clear_color_buffer(const color& value) noexcept;
render& set_viewport(u32 x, u32 y, u32 w, u32 h) noexcept; render& set_viewport(const v2u& pos, const v2u& size) noexcept;
render& set_render_target(const render_target_ptr& rt) noexcept; render& set_render_target(const render_target_ptr& rt) noexcept;
private: private:
class internal_state; class internal_state;

View File

@@ -214,7 +214,7 @@ int e2d_main() {
the<render>() the<render>()
.set_render_target(rt) .set_render_target(rt)
.set_viewport(0, 0, rt->size().x, rt->size().y) .set_viewport(v2u::zero(), rt->size())
.clear_depth_buffer(1.f) .clear_depth_buffer(1.f)
.clear_stencil_buffer(0) .clear_stencil_buffer(0)
.clear_color_buffer({0.f, 0.4f, 0.f, 1.f}) .clear_color_buffer({0.f, 0.4f, 0.f, 1.f})
@@ -228,7 +228,7 @@ int e2d_main() {
the<render>() the<render>()
.set_render_target(nullptr) .set_render_target(nullptr)
.set_viewport(0, 0, the<window>().real_size().x, the<window>().real_size().y) .set_viewport(v2u::zero(), the<window>().real_size())
.clear_depth_buffer(1.f) .clear_depth_buffer(1.f)
.clear_stencil_buffer(0) .clear_stencil_buffer(0)
.clear_color_buffer({1.f, 0.4f, 0.f, 1.f}) .clear_color_buffer({1.f, 0.4f, 0.f, 1.f})

View File

@@ -437,49 +437,78 @@ namespace e2d
// render // render
// //
render::render(debug& debug, window& window) render::render(debug& ndebug, window& nwindow)
: state_(new internal_state(debug, window)) { : state_(new internal_state(ndebug, nwindow))
{
E2D_ASSERT(
std::this_thread::get_id() ==
modules::main_thread<window>());
if ( glewInit() != GLEW_OK ) { if ( glewInit() != GLEW_OK ) {
throw bad_render_operation(); throw bad_render_operation();
} }
opengl::gl_trace_info(debug);
opengl::gl_trace_limits(debug); opengl::gl_trace_info(ndebug);
opengl::gl_trace_limits(ndebug);
GL_CHECK_CODE(state_->dbg(), glPixelStorei(GL_PACK_ALIGNMENT, 1)); GL_CHECK_CODE(state_->dbg(), glPixelStorei(GL_PACK_ALIGNMENT, 1));
GL_CHECK_CODE(state_->dbg(), glPixelStorei(GL_UNPACK_ALIGNMENT, 1)); GL_CHECK_CODE(state_->dbg(), glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
} }
render::~render() noexcept = default; render::~render() noexcept = default;
shader_ptr render::create_shader( shader_ptr render::create_shader(
input_stream_uptr vertex, const str& vertex_source,
input_stream_uptr fragment) const str& fragment_source)
{ {
str vertex_str; E2D_ASSERT(
gl_shader_id vs = streams::try_read_tail(vertex_str, vertex) std::this_thread::get_id() ==
? gl_compile_shader(state_->dbg(), vertex_str, GL_VERTEX_SHADER) modules::main_thread<render>());
: gl_shader_id(state_->dbg());
gl_shader_id vs = gl_compile_shader(
state_->dbg(), vertex_source, GL_VERTEX_SHADER);
if ( vs.empty() ) { if ( vs.empty() ) {
return nullptr; return nullptr;
} }
str fragment_str;
gl_shader_id fs = streams::try_read_tail(fragment_str, fragment) gl_shader_id fs = gl_compile_shader(
? gl_compile_shader(state_->dbg(), fragment_str, GL_FRAGMENT_SHADER) state_->dbg(), fragment_source, GL_FRAGMENT_SHADER);
: gl_shader_id(state_->dbg());
if ( fs.empty() ) { if ( fs.empty() ) {
return nullptr; return nullptr;
} }
gl_program_id ps = gl_link_program( gl_program_id ps = gl_link_program(
state_->dbg(), std::move(vs), std::move(fs)); state_->dbg(), std::move(vs), std::move(fs));
if ( ps.empty() ) { if ( ps.empty() ) {
return nullptr; return nullptr;
} }
return std::make_shared<shader>( return std::make_shared<shader>(
std::make_unique<shader::internal_state>( std::make_unique<shader::internal_state>(
state_->dbg(), std::move(ps))); state_->dbg(), std::move(ps)));
} }
shader_ptr render::create_shader(
const input_stream_uptr& vertex,
const input_stream_uptr& fragment)
{
E2D_ASSERT(
std::this_thread::get_id() ==
modules::main_thread<render>());
str vertex_source, fragment_source;
return streams::try_read_tail(vertex_source, vertex)
&& streams::try_read_tail(fragment_source, fragment)
? create_shader(vertex_source, fragment_source)
: nullptr;
}
texture_ptr render::create_texture( texture_ptr render::create_texture(
const image& image) const image& image)
{ {
E2D_ASSERT(
std::this_thread::get_id() ==
modules::main_thread<render>());
gl_texture_id id = gl_texture_id::create( gl_texture_id id = gl_texture_id::create(
state_->dbg(), GL_TEXTURE_2D); state_->dbg(), GL_TEXTURE_2D);
if ( id.empty() ) { if ( id.empty() ) {
@@ -487,6 +516,7 @@ namespace e2d
"failed to create texture id"); "failed to create texture id");
return nullptr; return nullptr;
} }
const pixel_declaration decl = const pixel_declaration decl =
convert_image_data_format_to_pixel_declaration(image.format()); convert_image_data_format_to_pixel_declaration(image.format());
with_gl_bind_texture(state_->dbg(), id, [this, &id, &image, &decl]() noexcept { with_gl_bind_texture(state_->dbg(), id, [this, &id, &image, &decl]() noexcept {
@@ -517,6 +547,7 @@ namespace e2d
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
#endif #endif
}); });
return std::make_shared<texture>( return std::make_shared<texture>(
std::make_unique<texture::internal_state>( std::make_unique<texture::internal_state>(
state_->dbg(), std::move(id), image.size(), decl)); state_->dbg(), std::move(id), image.size(), decl));
@@ -525,6 +556,10 @@ namespace e2d
texture_ptr render::create_texture( texture_ptr render::create_texture(
const input_stream_uptr& image_stream) const input_stream_uptr& image_stream)
{ {
E2D_ASSERT(
std::this_thread::get_id() ==
modules::main_thread<render>());
image image; image image;
if ( !images::try_load_image(image, image_stream) ) { if ( !images::try_load_image(image, image_stream) ) {
return nullptr; return nullptr;
@@ -536,6 +571,10 @@ namespace e2d
const v2u& size, const v2u& size,
const pixel_declaration& decl) const pixel_declaration& decl)
{ {
E2D_ASSERT(
std::this_thread::get_id() ==
modules::main_thread<render>());
gl_texture_id id = gl_texture_id::create( gl_texture_id id = gl_texture_id::create(
state_->dbg(), GL_TEXTURE_2D); state_->dbg(), GL_TEXTURE_2D);
if ( id.empty() ) { if ( id.empty() ) {
@@ -543,6 +582,7 @@ namespace e2d
"failed to create texture id"); "failed to create texture id");
return nullptr; return nullptr;
} }
with_gl_bind_texture(state_->dbg(), id, [this, &id, &size, &decl]() noexcept { with_gl_bind_texture(state_->dbg(), id, [this, &id, &size, &decl]() noexcept {
if ( decl.is_compressed() ) { if ( decl.is_compressed() ) {
buffer empty_data(decl.bits_per_pixel() * size.x * size.y / 8); buffer empty_data(decl.bits_per_pixel() * size.x * size.y / 8);
@@ -572,6 +612,7 @@ namespace e2d
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
#endif #endif
}); });
return std::make_shared<texture>( return std::make_shared<texture>(
std::make_unique<texture::internal_state>( std::make_unique<texture::internal_state>(
state_->dbg(), std::move(id), size, decl)); state_->dbg(), std::move(id), size, decl));
@@ -582,12 +623,17 @@ namespace e2d
const index_declaration& decl, const index_declaration& decl,
index_buffer::usage usage) index_buffer::usage usage)
{ {
E2D_ASSERT(
std::this_thread::get_id() ==
modules::main_thread<render>());
E2D_ASSERT(indices.size() % decl.bytes_per_index() == 0); E2D_ASSERT(indices.size() % decl.bytes_per_index() == 0);
gl_buffer_id id = gl_compile_index_buffer( gl_buffer_id id = gl_compile_index_buffer(
state_->dbg(), indices, usage); state_->dbg(), indices, usage);
if ( id.empty() ) { if ( id.empty() ) {
return nullptr; return nullptr;
} }
return std::make_shared<index_buffer>( return std::make_shared<index_buffer>(
std::make_unique<index_buffer::internal_state>( std::make_unique<index_buffer::internal_state>(
state_->dbg(), std::move(id), indices.size(), decl)); state_->dbg(), std::move(id), indices.size(), decl));
@@ -598,12 +644,17 @@ namespace e2d
const vertex_declaration& decl, const vertex_declaration& decl,
vertex_buffer::usage usage) vertex_buffer::usage usage)
{ {
E2D_ASSERT(
std::this_thread::get_id() ==
modules::main_thread<render>());
E2D_ASSERT(vertices.size() % decl.bytes_per_vertex() == 0); E2D_ASSERT(vertices.size() % decl.bytes_per_vertex() == 0);
gl_buffer_id id = gl_compile_vertex_buffer( gl_buffer_id id = gl_compile_vertex_buffer(
state_->dbg(), vertices, usage); state_->dbg(), vertices, usage);
if ( id.empty() ) { if ( id.empty() ) {
return nullptr; return nullptr;
} }
return std::make_shared<vertex_buffer>( return std::make_shared<vertex_buffer>(
std::make_unique<vertex_buffer::internal_state>( std::make_unique<vertex_buffer::internal_state>(
state_->dbg(), std::move(id), vertices.size(), decl)); state_->dbg(), std::move(id), vertices.size(), decl));
@@ -615,6 +666,10 @@ namespace e2d
const pixel_declaration& depth_decl, const pixel_declaration& depth_decl,
render_target::external_texture external_texture) render_target::external_texture external_texture)
{ {
E2D_ASSERT(
std::this_thread::get_id() ==
modules::main_thread<render>());
E2D_ASSERT( E2D_ASSERT(
depth_decl.is_depth() && depth_decl.is_depth() &&
color_decl.is_color() && color_decl.is_color() &&
@@ -712,6 +767,10 @@ namespace e2d
const material& mat, const material& mat,
const geometry& geo) const geometry& geo)
{ {
E2D_ASSERT(
std::this_thread::get_id() ==
modules::main_thread<render>());
draw(mat, geo, property_block()); draw(mat, geo, property_block());
} }
@@ -720,6 +779,10 @@ namespace e2d
const geometry& geo, const geometry& geo,
const property_block& props) const property_block& props)
{ {
E2D_ASSERT(
std::this_thread::get_id() ==
modules::main_thread<render>());
for ( std::size_t i = 0; i < mat.pass_count(); ++i ) { for ( std::size_t i = 0; i < mat.pass_count(); ++i ) {
const pass_state& pass = mat.pass(i); const pass_state& pass = mat.pass(i);
const property_block main_props = property_block() const property_block main_props = property_block()
@@ -736,6 +799,10 @@ namespace e2d
} }
render& render::clear_depth_buffer(f32 value) noexcept { 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(); const render_target_ptr& rt = state_->render_target();
if ( !rt || rt->state().depth() || !rt->state().depth_rb().empty() ) { if ( !rt || rt->state().depth() || !rt->state().depth_rb().empty() ) {
GL_CHECK_CODE(state_->dbg(), glClearDepth( GL_CHECK_CODE(state_->dbg(), glClearDepth(
@@ -746,6 +813,10 @@ namespace e2d
} }
render& render::clear_stencil_buffer(u8 value) noexcept { render& render::clear_stencil_buffer(u8 value) noexcept {
E2D_ASSERT(
std::this_thread::get_id() ==
modules::main_thread<render>());
const render_target_ptr& rt = state_->render_target(); const render_target_ptr& rt = state_->render_target();
if ( !rt || rt->state().depth() || !rt->state().depth_rb().empty() ) { if ( !rt || rt->state().depth() || !rt->state().depth_rb().empty() ) {
GL_CHECK_CODE(state_->dbg(), glClearStencil( GL_CHECK_CODE(state_->dbg(), glClearStencil(
@@ -756,6 +827,10 @@ namespace e2d
} }
render& render::clear_color_buffer(const color& value) noexcept { render& render::clear_color_buffer(const color& value) noexcept {
E2D_ASSERT(
std::this_thread::get_id() ==
modules::main_thread<render>());
const render_target_ptr& rt = state_->render_target(); const render_target_ptr& rt = state_->render_target();
if ( !rt || rt->state().color() || !rt->state().color_rb().empty() ) { if ( !rt || rt->state().color() || !rt->state().color_rb().empty() ) {
GL_CHECK_CODE(state_->dbg(), glClearColor( GL_CHECK_CODE(state_->dbg(), glClearColor(
@@ -768,16 +843,24 @@ namespace e2d
return *this; return *this;
} }
render& render::set_viewport(u32 x, u32 y, u32 w, u32 h) noexcept { render& render::set_viewport(const v2u& pos, const v2u& size) noexcept {
E2D_ASSERT(
std::this_thread::get_id() ==
modules::main_thread<render>());
GL_CHECK_CODE(state_->dbg(), glViewport( GL_CHECK_CODE(state_->dbg(), glViewport(
math::numeric_cast<GLint>(x), math::numeric_cast<GLint>(pos.x),
math::numeric_cast<GLint>(y), math::numeric_cast<GLint>(pos.y),
math::numeric_cast<GLsizei>(w), math::numeric_cast<GLsizei>(size.x),
math::numeric_cast<GLsizei>(h))); math::numeric_cast<GLsizei>(size.y)));
return *this; return *this;
} }
render& render::set_render_target(const render_target_ptr& rt) noexcept { render& render::set_render_target(const render_target_ptr& rt) noexcept {
E2D_ASSERT(
std::this_thread::get_id() ==
modules::main_thread<render>());
state_->set_render_target(rt); state_->set_render_target(rt);
return *this; return *this;
} }