diff --git a/tensorflow_graphics/rendering/opengl/BUILD b/tensorflow_graphics/rendering/opengl/BUILD index f8b6aacda..329c29074 100644 --- a/tensorflow_graphics/rendering/opengl/BUILD +++ b/tensorflow_graphics/rendering/opengl/BUILD @@ -248,6 +248,7 @@ py_test( cc_library( name = "rasterizer", + srcs = ["rasterizer.cc"], hdrs = ["rasterizer.h"], deps = [ ":gl_program", @@ -303,8 +304,10 @@ tf_custom_op_library( "gl_shader_storage_buffer.cc", "gl_shader_storage_buffer.h", "macros.h", + "rasterizer.cc", "rasterizer.h", "rasterizer_op.cc", + "rasterizer_with_context.cc", "rasterizer_with_context.h", "thread_safe_resource_pool.h", ], @@ -362,6 +365,7 @@ py_test( cc_library( name = "rasterizer_with_context", + srcs = ["rasterizer_with_context.cc"], hdrs = ["rasterizer_with_context.h"], deps = [ ":egl_offscreen_context", @@ -384,6 +388,7 @@ cc_test( ":thread_safe_resource_pool", "//third_party/tensorflow/core:lib", "//third_party/tensorflow/core:test", + "@com_google_absl//absl/types:span", "@com_google_googletest//:gtest_main", ], ) diff --git a/tensorflow_graphics/rendering/opengl/rasterizer.cc b/tensorflow_graphics/rendering/opengl/rasterizer.cc new file mode 100644 index 000000000..7d3feb769 --- /dev/null +++ b/tensorflow_graphics/rendering/opengl/rasterizer.cc @@ -0,0 +1,99 @@ +/* Copyright 2019 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ +#include "tensorflow_graphics/rendering/opengl/rasterizer.h" + +Rasterizer::Rasterizer( + std::unique_ptr&& program, + std::unique_ptr&& render_targets, float clear_r, + float clear_g, float clear_b, float clear_depth) + : program_(std::move(program)), + render_targets_(std::move(render_targets)), + clear_r_(clear_r), + clear_g_(clear_g), + clear_b_(clear_b), + clear_depth_(clear_depth) {} + +Rasterizer::~Rasterizer() {} + +void Rasterizer::Reset() { + program_.reset(); + render_targets_.reset(); + for (auto&& buffer : shader_storage_buffers_) buffer.second.reset(); +} + +tensorflow::Status Rasterizer::Render(int num_points, + absl::Span result) { + return RenderImpl(num_points, result); +} + +tensorflow::Status Rasterizer::Render(int num_points, + absl::Span result) { + return RenderImpl(num_points, result); +} + +tensorflow::Status Rasterizer::SetUniformMatrix( + const std::string& name, int num_columns, int num_rows, bool transpose, + absl::Span matrix) { + if (size_t(num_rows * num_columns) != matrix.size()) + return TFG_INTERNAL_ERROR("num_rows * num_columns != matrix.size()"); + + typedef void (*setter_fn)(GLint location, GLsizei count, GLboolean transpose, + const GLfloat* value); + + static const auto type_mapping = + std::unordered_map>({ + {GL_FLOAT_MAT2, std::make_tuple(2, 2, glUniformMatrix2fv)}, + {GL_FLOAT_MAT3, std::make_tuple(3, 3, glUniformMatrix3fv)}, + {GL_FLOAT_MAT4, std::make_tuple(4, 4, glUniformMatrix4fv)}, + {GL_FLOAT_MAT2x3, std::make_tuple(2, 3, glUniformMatrix2x3fv)}, + {GL_FLOAT_MAT2x4, std::make_tuple(2, 4, glUniformMatrix2x4fv)}, + {GL_FLOAT_MAT3x2, std::make_tuple(3, 2, glUniformMatrix3x2fv)}, + {GL_FLOAT_MAT3x4, std::make_tuple(3, 4, glUniformMatrix3x4fv)}, + {GL_FLOAT_MAT4x2, std::make_tuple(4, 2, glUniformMatrix4x2fv)}, + {GL_FLOAT_MAT4x3, std::make_tuple(4, 3, glUniformMatrix4x3fv)}, + }); + + GLint uniform_type; + GLenum property = GL_TYPE; + + TF_RETURN_IF_ERROR(program_->GetResourceProperty( + name, GL_UNIFORM, 1, &property, 1, &uniform_type)); + + // Is a resource active under that name? + if (uniform_type == GLint(GL_INVALID_INDEX)) + return TFG_INTERNAL_ERROR("GL_INVALID_INDEX"); + + auto type_info = type_mapping.find(uniform_type); + if (type_info == type_mapping.end()) + return TFG_INTERNAL_ERROR("Unsupported type"); + if (std::get<0>(type_info->second) != num_columns || + std::get<1>(type_info->second) != num_rows) + return TFG_INTERNAL_ERROR("Invalid dimensions"); + + GLint uniform_location; + property = GL_LOCATION; + TF_RETURN_IF_ERROR(program_->GetResourceProperty( + name, GL_UNIFORM, 1, &property, 1, &uniform_location)); + + TF_RETURN_IF_ERROR(program_->Use()); + auto program_cleanup = MakeCleanup([this]() { return program_->Detach(); }); + + // Specify the value of the uniform in the current program. + TFG_RETURN_IF_GL_ERROR(std::get<2>(type_info->second)( + uniform_location, 1, transpose ? GL_TRUE : GL_FALSE, matrix.data())); + + // Cleanup the program; no program is active at this point. + return tensorflow::Status::OK(); +} diff --git a/tensorflow_graphics/rendering/opengl/rasterizer.h b/tensorflow_graphics/rendering/opengl/rasterizer.h index af6d36b32..bba8dc4a7 100644 --- a/tensorflow_graphics/rendering/opengl/rasterizer.h +++ b/tensorflow_graphics/rendering/opengl/rasterizer.h @@ -24,16 +24,17 @@ limitations under the License. #include "tensorflow_graphics/rendering/opengl/gl_shader_storage_buffer.h" #include "tensorflow_graphics/util/cleanup.h" -template class RasterizerWithContext; -template class Rasterizer { public: virtual ~Rasterizer(); // Creates a Rasterizer holding a valid OpenGL program and render buffers. // + // Note: the template argument defines the data type stored in the render + // buffer. See the documentation of RenderTargets::Create for more details. + // // Arguments: // * width: width of the render buffers. // * height: height of the render buffers. @@ -46,6 +47,7 @@ class Rasterizer { // Returns: // A tensorflow::Status object storing tensorflow::Status::OK() on success, // and an object of type tensorflow::errors otherwise. + template static tensorflow::Status Create(const int width, const int height, const std::string& vertex_shader_source, const std::string& geometry_shader_source, @@ -70,6 +72,7 @@ class Rasterizer { // Returns: // A tensorflow::Status object storing tensorflow::Status::OK() on success, // and an object of type tensorflow::errors otherwise. + template static tensorflow::Status Create(const int width, const int height, const std::string& vertex_shader_source, const std::string& geometry_shader_source, @@ -83,12 +86,15 @@ class Rasterizer { // Arguments: // * num_points: the number of primitives to render. // * result: if the method succeeds, a buffer that stores the rendering - // result. + // result. This buffer must be of size 4 * width * height, where the values + // of width and height must at least match those used in when calling Create. // // Returns: // A tensorflow::Status object storing tensorflow::Status::OK() on success, // and an object of type tensorflow::errors otherwise. - virtual tensorflow::Status Render(int num_points, absl::Span result); + virtual tensorflow::Status Render(int num_points, absl::Span result); + virtual tensorflow::Status Render(int num_points, + absl::Span result); // Uploads data to a shader storage buffer. // @@ -99,9 +105,9 @@ class Rasterizer { // Returns: // A tensorflow::Status object storing tensorflow::Status::OK() on success, // and an object of type tensorflow::errors otherwise. - template + template tensorflow::Status SetShaderStorageBuffer(const std::string& name, - absl::Span data); + absl::Span data); // Specifies the value of a uniform matrix. // @@ -132,6 +138,8 @@ class Rasterizer { Rasterizer(Rasterizer&&) = delete; Rasterizer& operator=(const Rasterizer&) = delete; Rasterizer& operator=(Rasterizer&&) = delete; + template + tensorflow::Status RenderImpl(int num_points, absl::Span result); void Reset(); std::unique_ptr program_; @@ -141,40 +149,27 @@ class Rasterizer { shader_storage_buffers_; float clear_r_, clear_g_, clear_b_, clear_depth_; - friend class RasterizerWithContext; + friend class RasterizerWithContext; }; template -Rasterizer::Rasterizer( - std::unique_ptr&& program, - std::unique_ptr&& render_targets, float clear_r, - float clear_g, float clear_b, float clear_depth) - : program_(std::move(program)), - render_targets_(std::move(render_targets)), - clear_r_(clear_r), - clear_g_(clear_g), - clear_b_(clear_b), - clear_depth_(clear_depth) {} - -template -Rasterizer::~Rasterizer() {} - -template -tensorflow::Status Rasterizer::Create( - const int width, const int height, const std::string& vertex_shader_source, - const std::string& geometry_shader_source, - const std::string& fragment_shader_source, - std::unique_ptr* rasterizer) { - return Create(width, height, vertex_shader_source, geometry_shader_source, - fragment_shader_source, 0.0, 0.0, 0.0, 1.0, rasterizer); +tensorflow::Status Rasterizer::Create(const int width, const int height, + const std::string& vertex_shader_source, + const std::string& geometry_shader_source, + const std::string& fragment_shader_source, + std::unique_ptr* rasterizer) { + return Create(width, height, vertex_shader_source, geometry_shader_source, + fragment_shader_source, 0.0, 0.0, 0.0, 1.0, rasterizer); } template -tensorflow::Status Rasterizer::Create( - const int width, const int height, const std::string& vertex_shader_source, - const std::string& geometry_shader_source, - const std::string& fragment_shader_source, float clear_r, float clear_g, - float clear_b, float clear_depth, std::unique_ptr* rasterizer) { +tensorflow::Status Rasterizer::Create(const int width, const int height, + const std::string& vertex_shader_source, + const std::string& geometry_shader_source, + const std::string& fragment_shader_source, + float clear_r, float clear_g, + float clear_b, float clear_depth, + std::unique_ptr* rasterizer) { std::unique_ptr program; std::unique_ptr render_targets; std::vector> shaders = { @@ -193,7 +188,8 @@ tensorflow::Status Rasterizer::Create( } template -tensorflow::Status Rasterizer::Render(int num_points, absl::Span result) { +tensorflow::Status Rasterizer::RenderImpl(int num_points, + absl::Span result) { const GLenum kProperty = GL_BUFFER_BINDING; TFG_RETURN_IF_GL_ERROR(glDisable(GL_BLEND)); @@ -228,6 +224,7 @@ tensorflow::Status Rasterizer::Render(int num_points, absl::Span result) { TFG_RETURN_IF_GL_ERROR(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)); TFG_RETURN_IF_GL_ERROR(glDrawArrays(GL_POINTS, 0, num_points)); + TF_RETURN_IF_ERROR(render_targets_->CopyPixelsInto(result)); // The program and framebuffer and released here. @@ -235,16 +232,8 @@ tensorflow::Status Rasterizer::Render(int num_points, absl::Span result) { } template -void Rasterizer::Reset() { - program_.reset(); - render_targets_.reset(); - for (auto&& buffer : shader_storage_buffers_) buffer.second.reset(); -} - -template -template -tensorflow::Status Rasterizer::SetShaderStorageBuffer( - const std::string& name, absl::Span data) { +tensorflow::Status Rasterizer::SetShaderStorageBuffer( + const std::string& name, absl::Span data) { // If the buffer does not exist, create it. if (shader_storage_buffers_.count(name) == 0) { std::unique_ptr shader_storage_buffer; @@ -259,60 +248,4 @@ tensorflow::Status Rasterizer::SetShaderStorageBuffer( return tensorflow::Status::OK(); } -template -tensorflow::Status Rasterizer::SetUniformMatrix( - const std::string& name, int num_columns, int num_rows, bool transpose, - absl::Span matrix) { - if (size_t(num_rows * num_columns) != matrix.size()) - return TFG_INTERNAL_ERROR("num_rows * num_columns != matrix.size()"); - - typedef void (*setter_fn)(GLint location, GLsizei count, GLboolean transpose, - const GLfloat* value); - - static const auto type_mapping = - std::unordered_map>({ - {GL_FLOAT_MAT2, std::make_tuple(2, 2, glUniformMatrix2fv)}, - {GL_FLOAT_MAT3, std::make_tuple(3, 3, glUniformMatrix3fv)}, - {GL_FLOAT_MAT4, std::make_tuple(4, 4, glUniformMatrix4fv)}, - {GL_FLOAT_MAT2x3, std::make_tuple(2, 3, glUniformMatrix2x3fv)}, - {GL_FLOAT_MAT2x4, std::make_tuple(2, 4, glUniformMatrix2x4fv)}, - {GL_FLOAT_MAT3x2, std::make_tuple(3, 2, glUniformMatrix3x2fv)}, - {GL_FLOAT_MAT3x4, std::make_tuple(3, 4, glUniformMatrix3x4fv)}, - {GL_FLOAT_MAT4x2, std::make_tuple(4, 2, glUniformMatrix4x2fv)}, - {GL_FLOAT_MAT4x3, std::make_tuple(4, 3, glUniformMatrix4x3fv)}, - }); - - GLint uniform_type; - GLenum property = GL_TYPE; - - TF_RETURN_IF_ERROR(program_->GetResourceProperty( - name, GL_UNIFORM, 1, &property, 1, &uniform_type)); - - // Is a resource active under that name? - if (uniform_type == GLint(GL_INVALID_INDEX)) - return TFG_INTERNAL_ERROR("GL_INVALID_INDEX"); - - auto type_info = type_mapping.find(uniform_type); - if (type_info == type_mapping.end()) - return TFG_INTERNAL_ERROR("Unsupported type"); - if (std::get<0>(type_info->second) != num_columns || - std::get<1>(type_info->second) != num_rows) - return TFG_INTERNAL_ERROR("Invalid dimensions"); - - GLint uniform_location; - property = GL_LOCATION; - TF_RETURN_IF_ERROR(program_->GetResourceProperty( - name, GL_UNIFORM, 1, &property, 1, &uniform_location)); - - TF_RETURN_IF_ERROR(program_->Use()); - auto program_cleanup = MakeCleanup([this]() { return program_->Detach(); }); - - // Specify the value of the uniform in the current program. - TFG_RETURN_IF_GL_ERROR(std::get<2>(type_info->second)( - uniform_location, 1, transpose ? GL_TRUE : GL_FALSE, matrix.data())); - - // Cleanup the program; no program is active at this point. - return tensorflow::Status::OK(); -} - #endif // THIRD_PARTY_PY_TENSORFLOW_GRAPHICS_RENDERING_OPENGL_TESTS_RASTERIZER_H_ diff --git a/tensorflow_graphics/rendering/opengl/rasterizer_op.cc b/tensorflow_graphics/rendering/opengl/rasterizer_op.cc index c70c1f523..d633f397c 100644 --- a/tensorflow_graphics/rendering/opengl/rasterizer_op.cc +++ b/tensorflow_graphics/rendering/opengl/rasterizer_op.cc @@ -93,21 +93,21 @@ class RasterizeOp : public tensorflow::OpKernel { auto rasterizer_creator = [vertex_shader, geometry_shader, fragment_shader, red_clear, green_clear, blue_clear, depth_clear, - this](std::unique_ptr>* resource) + this](std::unique_ptr* resource) -> tensorflow::Status { - return RasterizerWithContext::Create( + return RasterizerWithContext::Create( output_resolution_.dim_size(1), output_resolution_.dim_size(0), vertex_shader, geometry_shader, fragment_shader, resource, red_clear, green_clear, blue_clear, depth_clear); }; rasterizer_pool_ = - std::unique_ptr>>( - new ThreadSafeResourcePool>( + std::unique_ptr>( + new ThreadSafeResourcePool( rasterizer_creator)); } void Compute(tensorflow::OpKernelContext* context) override { - std::unique_ptr> rasterizer; + std::unique_ptr rasterizer; OP_REQUIRES_OK(context, rasterizer_pool_->AcquireResource(&rasterizer)); OP_REQUIRES_OK(context, SetVariables(context, rasterizer)); @@ -118,12 +118,12 @@ class RasterizeOp : public tensorflow::OpKernel { private: tensorflow::Status SetVariables( tensorflow::OpKernelContext* context, - std::unique_ptr>& rasterizer); + std::unique_ptr& rasterizer); tensorflow::Status RenderImage( tensorflow::OpKernelContext* context, - std::unique_ptr>& rasterizer); + std::unique_ptr& rasterizer); - std::unique_ptr>> + std::unique_ptr> rasterizer_pool_; std::vector variable_names_; std::vector variable_kinds_; @@ -132,7 +132,7 @@ class RasterizeOp : public tensorflow::OpKernel { tensorflow::Status RasterizeOp::RenderImage( tensorflow::OpKernelContext* context, - std::unique_ptr>& rasterizer) { + std::unique_ptr& rasterizer) { tensorflow::Tensor* output_image; tensorflow::TensorShape output_image_shape( {output_resolution_.dim_size(0), output_resolution_.dim_size(1), 4}); @@ -149,7 +149,7 @@ tensorflow::Status RasterizeOp::RenderImage( tensorflow::Status RasterizeOp::SetVariables( tensorflow::OpKernelContext* context, - std::unique_ptr>& rasterizer) { + std::unique_ptr& rasterizer) { tensorflow::OpInputList variable_values; TF_RETURN_IF_ERROR(context->input_list("variable_values", &variable_values)); diff --git a/tensorflow_graphics/rendering/opengl/rasterizer_with_context.cc b/tensorflow_graphics/rendering/opengl/rasterizer_with_context.cc new file mode 100644 index 000000000..4ab0cf27d --- /dev/null +++ b/tensorflow_graphics/rendering/opengl/rasterizer_with_context.cc @@ -0,0 +1,89 @@ +/* Copyright 2019 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ +#include "tensorflow_graphics/rendering/opengl/rasterizer_with_context.h" + +RasterizerWithContext::RasterizerWithContext( + std::unique_ptr&& egl_context, + std::unique_ptr&& program, + std::unique_ptr&& render_targets, float clear_r, + float clear_g, float clear_b, float clear_depth) + : Rasterizer(std::move(program), std::move(render_targets), clear_r, + clear_g, clear_b, clear_depth), + egl_context_(std::move(egl_context)) {} + +RasterizerWithContext::~RasterizerWithContext() { + // Destroy the rasterizer in the correct EGL context. + auto status = egl_context_->MakeCurrent(); + if (status != tensorflow::Status::OK()) + std::cerr + << "~RasterizerWithContext: failure to set the context as current." + << std::endl; + // Reset all the members of the Rasterizer parent class before destroying the + // context. + this->Reset(); + // egl_context_ is destroyed here, which calls + // egl_offscreen_context::Release(). +} + +tensorflow::Status RasterizerWithContext::Create( + int width, int height, const std::string& vertex_shader_source, + const std::string& geometry_shader_source, + const std::string& fragment_shader_source, + std::unique_ptr* rasterizer_with_context, + float clear_r, float clear_g, float clear_b, float clear_depth) { + std::unique_ptr program; + std::unique_ptr render_targets; + std::vector> shaders; + std::unique_ptr offscreen_context; + + TF_RETURN_IF_ERROR(EGLOffscreenContext::Create(&offscreen_context)); + TF_RETURN_IF_ERROR(offscreen_context->MakeCurrent()); + // No need to have a MakeCleanup here as EGLOffscreenContext::Release() + // would be called on destruction of the offscreen_context object, which + // would happen here if the whole creation process was not successful. + + shaders.push_back(std::make_pair(vertex_shader_source, GL_VERTEX_SHADER)); + shaders.push_back(std::make_pair(geometry_shader_source, GL_GEOMETRY_SHADER)); + shaders.push_back(std::make_pair(fragment_shader_source, GL_FRAGMENT_SHADER)); + TF_RETURN_IF_ERROR(gl_utils::Program::Create(shaders, &program)); + TF_RETURN_IF_ERROR( + gl_utils::RenderTargets::Create(width, height, &render_targets)); + TF_RETURN_IF_ERROR(offscreen_context->Release()); + *rasterizer_with_context = + std::unique_ptr(new RasterizerWithContext( + std::move(offscreen_context), std::move(program), + std::move(render_targets), clear_r, clear_g, clear_b, clear_depth)); + return tensorflow::Status::OK(); +} + +tensorflow::Status RasterizerWithContext::Render(int num_points, + absl::Span result) { + TF_RETURN_IF_ERROR(egl_context_->MakeCurrent()); + auto context_cleanup = + MakeCleanup([this]() { return this->egl_context_->Release(); }); + TF_RETURN_IF_ERROR(Rasterizer::Render(num_points, result)); + // context_cleanup calls EGLOffscreenContext::Release here. + return tensorflow::Status::OK(); +} + +tensorflow::Status RasterizerWithContext::Render( + int num_points, absl::Span result) { + TF_RETURN_IF_ERROR(egl_context_->MakeCurrent()); + auto context_cleanup = + MakeCleanup([this]() { return this->egl_context_->Release(); }); + TF_RETURN_IF_ERROR(Rasterizer::Render(num_points, result)); + // context_cleanup calls EGLOffscreenContext::Release here. + return tensorflow::Status::OK(); +} diff --git a/tensorflow_graphics/rendering/opengl/rasterizer_with_context.h b/tensorflow_graphics/rendering/opengl/rasterizer_with_context.h index 886178e9b..6d2cf0736 100644 --- a/tensorflow_graphics/rendering/opengl/rasterizer_with_context.h +++ b/tensorflow_graphics/rendering/opengl/rasterizer_with_context.h @@ -20,8 +20,7 @@ limitations under the License. #include "tensorflow_graphics/util/cleanup.h" #include "tensorflow/core/lib/core/status.h" -template -class RasterizerWithContext : public Rasterizer { +class RasterizerWithContext : public Rasterizer { public: ~RasterizerWithContext(); @@ -49,7 +48,7 @@ class RasterizerWithContext : public Rasterizer { int width, int height, const std::string& vertex_shader_source, const std::string& geometry_shader_source, const std::string& fragment_shader_source, - std::unique_ptr>* rasterizer_with_context, + std::unique_ptr* rasterizer_with_context, float clear_r = 0.0f, float clear_g = 0.0f, float clear_b = 0.0f, float clear_depth = 1.0f); @@ -63,7 +62,9 @@ class RasterizerWithContext : public Rasterizer { // Returns: // A boolean set to false if any error occured during the process, and set // to true otherwise. - tensorflow::Status Render(int num_points, absl::Span result) override; + tensorflow::Status Render(int num_points, absl::Span result) override; + tensorflow::Status Render(int num_points, + absl::Span result) override; // Uploads data to a shader storage buffer. // @@ -74,9 +75,9 @@ class RasterizerWithContext : public Rasterizer { // Returns: // A boolean set to false if any error occured during the process, and set // to true otherwise. - template + template tensorflow::Status SetShaderStorageBuffer(const std::string& name, - absl::Span data); + absl::Span data); // Specifies the value of a uniform matrix. // @@ -93,9 +94,10 @@ class RasterizerWithContext : public Rasterizer { // Returns: // A boolean set to false if any error occured during the process, and set // to true otherwise. + template tensorflow::Status SetUniformMatrix(const std::string& name, int num_columns, int num_rows, bool transpose, - absl::Span matrix) override; + absl::Span matrix); private: RasterizerWithContext() = delete; @@ -113,96 +115,38 @@ class RasterizerWithContext : public Rasterizer { }; template -RasterizerWithContext::RasterizerWithContext( - std::unique_ptr&& egl_context, - std::unique_ptr&& program, - std::unique_ptr&& render_targets, float clear_r, - float clear_g, float clear_b, float clear_depth) - : egl_context_(std::move(egl_context)), - Rasterizer(std::move(program), std::move(render_targets), clear_r, - clear_g, clear_b, clear_depth) {} - -template -RasterizerWithContext::~RasterizerWithContext() { - // Destroy the rasterizer in the correct EGL context. - auto status = egl_context_->MakeCurrent(); - if (status != tensorflow::Status::OK()) - std::cerr - << "~RasterizerWithContext: failure to set the context as current." - << std::endl; - // Reset all the members of the Rasterizer parent class before destroying the - // context. - this->Reset(); - // egl_context_ is destroyed here, which calls - // egl_offscreen_context::Release(). -} - -template -tensorflow::Status RasterizerWithContext::Create( - int width, int height, const std::string& vertex_shader_source, - const std::string& geometry_shader_source, - const std::string& fragment_shader_source, - std::unique_ptr>* rasterizer_with_context, - float clear_r, float clear_g, float clear_b, float clear_depth) { - std::unique_ptr program; - std::unique_ptr render_targets; - std::vector> shaders; - std::unique_ptr offscreen_context; - - TF_RETURN_IF_ERROR(EGLOffscreenContext::Create(&offscreen_context)); - TF_RETURN_IF_ERROR(offscreen_context->MakeCurrent()); - // No need to have a MakeCleanup here as EGLOffscreenContext::Release() - // would be called on destruction of the offscreen_context object, which - // would happen here if the whole creation process was not successful. - - shaders.push_back(std::make_pair(vertex_shader_source, GL_VERTEX_SHADER)); - shaders.push_back(std::make_pair(geometry_shader_source, GL_GEOMETRY_SHADER)); - shaders.push_back(std::make_pair(fragment_shader_source, GL_FRAGMENT_SHADER)); - TF_RETURN_IF_ERROR(gl_utils::Program::Create(shaders, &program)); - TF_RETURN_IF_ERROR( - gl_utils::RenderTargets::Create(width, height, &render_targets)); - TF_RETURN_IF_ERROR(offscreen_context->Release()); - *rasterizer_with_context = - std::unique_ptr(new RasterizerWithContext( - std::move(offscreen_context), std::move(program), - std::move(render_targets), clear_r, clear_g, clear_b, clear_depth)); - return tensorflow::Status::OK(); -} - -template -tensorflow::Status RasterizerWithContext::Render(int num_points, - absl::Span result) { - TF_RETURN_IF_ERROR(egl_context_->MakeCurrent()); - auto context_cleanup = - MakeCleanup([this]() { this->egl_context_->Release(); }); - TF_RETURN_IF_ERROR(Rasterizer::Render(num_points, result)); - // context_cleanup calls EGLOffscreenContext::Release here. - return tensorflow::Status::OK(); -} - -template -template -tensorflow::Status RasterizerWithContext::SetShaderStorageBuffer( - const std::string& name, absl::Span data) { +tensorflow::Status RasterizerWithContext::SetShaderStorageBuffer( + const std::string& name, absl::Span data) { TF_RETURN_IF_ERROR(egl_context_->MakeCurrent()); auto context_cleanup = - MakeCleanup([this]() { this->egl_context_->Release(); }); - TF_RETURN_IF_ERROR(Rasterizer::SetShaderStorageBuffer(name, data)); + MakeCleanup([this]() { return this->egl_context_->Release(); }); + TF_RETURN_IF_ERROR(Rasterizer::SetShaderStorageBuffer(name, data)); // context_cleanup calls EGLOffscreenContext::Release here. return tensorflow::Status::OK(); } template -tensorflow::Status RasterizerWithContext::SetUniformMatrix( +tensorflow::Status RasterizerWithContext::SetUniformMatrix( const std::string& name, int num_columns, int num_rows, bool transpose, absl::Span matrix) { TF_RETURN_IF_ERROR(egl_context_->MakeCurrent()); auto context_cleanup = - MakeCleanup([this]() { this->egl_context_->Release(); }); - TF_RETURN_IF_ERROR(Rasterizer::SetUniformMatrix( - name, num_columns, num_rows, transpose, matrix)); + MakeCleanup([this]() { return this->egl_context_->Release(); }); + TF_RETURN_IF_ERROR(Rasterizer::SetUniformMatrix(name, num_columns, num_rows, + transpose, matrix)); // context_cleanup calls EGLOffscreenContext::Release here. return tensorflow::Status::OK(); } +// template +// tensorflow::Status RasterizerWithContext::Render( +// int num_points, absl::Span result) { +// TF_RETURN_IF_ERROR(egl_context_->MakeCurrent()); +// auto context_cleanup = +// MakeCleanup([this]() { return this->egl_context_->Release(); }); +// TF_RETURN_IF_ERROR(Rasterizer::Render(num_points, result)); +// // context_cleanup calls EGLOffscreenContext::Release here. +// return tensorflow::Status::OK(); +// } + #endif // THIRD_PARTY_PY_TENSORFLOW_GRAPHICS_RENDERING_OPENGL_RASTERIZER_WITH_CONTEXT_H_ diff --git a/tensorflow_graphics/rendering/opengl/tests/rasterizer_test.cc b/tensorflow_graphics/rendering/opengl/tests/rasterizer_test.cc index 64bda65b4..2ee8b02c0 100644 --- a/tensorflow_graphics/rendering/opengl/tests/rasterizer_test.cc +++ b/tensorflow_graphics/rendering/opengl/tests/rasterizer_test.cc @@ -103,23 +103,23 @@ const std::string kGeometryShaderCode = TEST(RasterizerTest, TestCreate) { std::unique_ptr context; - std::unique_ptr> rasterizer; + std::unique_ptr rasterizer; TF_ASSERT_OK(EGLOffscreenContext::Create(&context)); TF_ASSERT_OK(context->MakeCurrent()); TF_EXPECT_OK( - (Rasterizer::Create(3, 2, kEmptyShaderCode, kEmptyShaderCode, + (Rasterizer::Create(3, 2, kEmptyShaderCode, kEmptyShaderCode, kEmptyShaderCode, &rasterizer))); } TEST(RasterizerTest, TestSetShaderStorageBuffer) { std::unique_ptr context; - std::unique_ptr> rasterizer; + std::unique_ptr rasterizer; TF_ASSERT_OK(EGLOffscreenContext::Create(&context)); TF_ASSERT_OK(context->MakeCurrent()); TF_ASSERT_OK( - (Rasterizer::Create(3, 2, kEmptyShaderCode, kEmptyShaderCode, + (Rasterizer::Create(3, 2, kEmptyShaderCode, kEmptyShaderCode, kEmptyShaderCode, &rasterizer))); // Fronto-parallel triangle at depth 1. @@ -132,12 +132,12 @@ TEST(RasterizerTest, TestSetShaderStorageBuffer) { TEST(RasterizerTest, TestSetUniformMatrix) { std::unique_ptr context; - std::unique_ptr> rasterizer; + std::unique_ptr rasterizer; TF_ASSERT_OK(EGLOffscreenContext::Create(&context)); TF_ASSERT_OK(context->MakeCurrent()); TF_ASSERT_OK( - (Rasterizer::Create(3, 2, kEmptyShaderCode, kGeometryShaderCode, + (Rasterizer::Create(3, 2, kEmptyShaderCode, kGeometryShaderCode, kFragmentShaderCode, &rasterizer))); const std::string resource_name = "view_projection_matrix"; @@ -157,7 +157,7 @@ TYPED_TEST(RasterizerInterfaceTest, TestRender) { -1.73205, 0.0, 0.0, 0.0, 0.0, 1.73205, 0.0, 0.0, 0.0, 0.0, 1.002002, 1.0, 0.0, 0.0, -0.02002002, 0.0}; std::unique_ptr context; - std::unique_ptr> rasterizer; + std::unique_ptr rasterizer; const int kWidth = 3; const int kHeight = 3; float max_gl_value = 255.0f; @@ -166,7 +166,7 @@ TYPED_TEST(RasterizerInterfaceTest, TestRender) { TF_ASSERT_OK(EGLOffscreenContext::Create(&context)); TF_ASSERT_OK(context->MakeCurrent()); - TF_ASSERT_OK((Rasterizer::Create( + TF_ASSERT_OK((Rasterizer::Create( kWidth, kHeight, kEmptyShaderCode, kGeometryShaderCode, kFragmentShaderCode, &rasterizer))); TF_ASSERT_OK(rasterizer->SetUniformMatrix("view_projection_matrix", 4, 4, diff --git a/tensorflow_graphics/rendering/opengl/tests/rasterizer_with_context_test.cc b/tensorflow_graphics/rendering/opengl/tests/rasterizer_with_context_test.cc index 8658b7ef6..1882afde6 100644 --- a/tensorflow_graphics/rendering/opengl/tests/rasterizer_with_context_test.cc +++ b/tensorflow_graphics/rendering/opengl/tests/rasterizer_with_context_test.cc @@ -18,12 +18,11 @@ limitations under the License. #include #include "gtest/gtest.h" +#include "absl/types/span.h" +#include "tensorflow_graphics/rendering/opengl/thread_safe_resource_pool.h" #include "tensorflow/core/lib/core/status.h" #include "tensorflow/core/lib/core/status_test_util.h" -#include "tensorflow_graphics/rendering/opengl/thread_safe_resource_pool.h" - - namespace { const std::string kEmptyShaderCode = @@ -106,11 +105,11 @@ const std::string geometry_shader_code = TEST(RasterizerWithContextTest, TestCreate) { constexpr int kWidth = 5; constexpr int kHeight = 5; - std::unique_ptr> rasterizer_with_context; + std::unique_ptr rasterizer_with_context; - TF_CHECK_OK(RasterizerWithContext::Create( - kWidth, kHeight, kEmptyShaderCode, kEmptyShaderCode, kEmptyShaderCode, - &rasterizer_with_context)); + TF_CHECK_OK(RasterizerWithContext::Create(kWidth, kHeight, kEmptyShaderCode, + kEmptyShaderCode, kEmptyShaderCode, + &rasterizer_with_context)); } TEST(RasterizerWithContextTest, TestRenderSingleThread) { @@ -121,9 +120,9 @@ TEST(RasterizerWithContextTest, TestRenderSingleThread) { constexpr float kClearBlue = 0.3; constexpr int kNumRenders = 100; constexpr int kNumVertices = 0; - std::unique_ptr> rasterizer_with_context; + std::unique_ptr rasterizer_with_context; - TF_ASSERT_OK(RasterizerWithContext::Create( + TF_ASSERT_OK(RasterizerWithContext::Create( kWidth, kHeight, kEmptyShaderCode, geometry_shader_code, fragment_shader_code, &rasterizer_with_context, kClearRed, kClearGreen, kClearBlue)); @@ -147,7 +146,7 @@ constexpr float kIncrementBlue = 0.003; template static tensorflow::Status rasterizer_with_context_creator( - std::unique_ptr> *resource) { + std::unique_ptr *resource) { static float red_clear = 0.0; static float green_clear = 0.0; static float blue_clear = 0.0; @@ -155,7 +154,7 @@ static tensorflow::Status rasterizer_with_context_creator( red_clear += kIncrementRed; green_clear += kIncrementGreen; blue_clear += kIncrementBlue; - return RasterizerWithContext::Create( + return RasterizerWithContext::Create( kWidth, kHeight, kEmptyShaderCode, geometry_shader_code, fragment_shader_code, resource, red_clear, green_clear, blue_clear); } @@ -167,16 +166,17 @@ TEST(RasterizerWithContextTest, TestRenderMultiThread) { constexpr int pixel_query = kWidth * kHeight / 2; std::array threads; std::array, kNumThreads> buffers; - std::array>, kNumThreads> - rasterizers; + std::array, kNumThreads> rasterizers; + auto rendering_function_pointer = + static_cast)>(&RasterizerWithContext::Render); for (int i = 0; i < kNumThreads; ++i) { buffers[i].resize(kWidth * kHeight * 4); TF_ASSERT_OK( (rasterizer_with_context_creator(&rasterizers[i]))); - threads[i] = - std::thread(&RasterizerWithContext::Render, rasterizers[i].get(), - 0, absl::MakeSpan(buffers[i])); + threads[i] = std::thread(rendering_function_pointer, rasterizers[i].get(), + 0, absl::MakeSpan(buffers[i])); } // Wait for each thread to be done, accumulate values from the rendered @@ -206,17 +206,18 @@ TEST(RasterizerWithContextTest, TestRenderMultiThreadLoop) { typedef float buffer_type; std::array threads; std::array, kNumThreads> buffers; - std::array>, kNumThreads> - rasterizers; + std::array, kNumThreads> rasterizers; + auto rendering_function_pointer = + static_cast)>(&RasterizerWithContext::Render); // Launch all the threads. for (int i = 0; i < kNumThreads; ++i) { buffers[i].resize(kWidth * kHeight * 4); TF_ASSERT_OK( (rasterizer_with_context_creator(&rasterizers[i]))); - threads[i] = - std::thread(&RasterizerWithContext::Render, rasterizers[i].get(), - 0, absl::MakeSpan(buffers[i])); + threads[i] = std::thread(rendering_function_pointer, rasterizers[i].get(), + 0, absl::MakeSpan(buffers[i])); } for (int l = 0; l < kNumLoops; ++l) { @@ -226,9 +227,8 @@ TEST(RasterizerWithContextTest, TestRenderMultiThreadLoop) { } // Launch another set of rendering threads. for (int i = 0; i < kNumThreads; ++i) { - threads[i] = - std::thread(&RasterizerWithContext::Render, - rasterizers[i].get(), 0, absl::MakeSpan(buffers[i])); + threads[i] = std::thread(rendering_function_pointer, rasterizers[i].get(), + 0, absl::MakeSpan(buffers[i])); } }