From: Mikko Rasa Date: Sat, 3 Sep 2022 13:38:03 +0000 (+0300) Subject: Add tessellation shader support to the engine X-Git-Url: http://git.tdb.fi/?a=commitdiff_plain;h=9eb9f592d37e9a1e05c2ff70887a1c5f26b98864;p=libs%2Fgl.git Add tessellation shader support to the engine --- diff --git a/extensions/arb_tessellation_shader.glext b/extensions/arb_tessellation_shader.glext new file mode 100644 index 00000000..7fb6202b --- /dev/null +++ b/extensions/arb_tessellation_shader.glext @@ -0,0 +1 @@ +extension ARB_tessellation_shader diff --git a/source/backends/opengl/batch_backend.cpp b/source/backends/opengl/batch_backend.cpp index d80c11cc..2bd3c837 100644 --- a/source/backends/opengl/batch_backend.cpp +++ b/source/backends/opengl/batch_backend.cpp @@ -1,3 +1,4 @@ +#include #include #include "batch_backend.h" @@ -7,7 +8,10 @@ namespace GL { OpenGLBatch::OpenGLBatch(PrimitiveType t): gl_prim_type(get_gl_primitive_type(t)), gl_index_type(GL_UNSIGNED_SHORT) -{ } +{ + if(t==PATCHES) + static Require _req(ARB_tessellation_shader); +} bool OpenGLBatch::check_restart(bool require) { diff --git a/source/backends/opengl/pipelinestate_backend.cpp b/source/backends/opengl/pipelinestate_backend.cpp index 8ffa47fc..204e8139 100644 --- a/source/backends/opengl/pipelinestate_backend.cpp +++ b/source/backends/opengl/pipelinestate_backend.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include "blend.h" @@ -180,6 +181,13 @@ void OpenGLPipelineState::apply() const } } + if(changes&PipelineState::PATCH_SIZE) + if(self.patch_size) + { + static Require _req(ARB_tessellation_shader); + glPatchParameteri(GL_PATCH_VERTICES, self.patch_size); + } + if(changes&PipelineState::FACE_CULL) { glFrontFace(self.front_face==CLOCKWISE ? GL_CW : GL_CCW); diff --git a/source/backends/opengl/primitivetype_backend.cpp b/source/backends/opengl/primitivetype_backend.cpp index 42ee9f26..a3c862c0 100644 --- a/source/backends/opengl/primitivetype_backend.cpp +++ b/source/backends/opengl/primitivetype_backend.cpp @@ -17,6 +17,7 @@ unsigned get_gl_primitive_type(PrimitiveType pt) case TRIANGLES: return GL_TRIANGLES; case TRIANGLE_STRIP: return GL_TRIANGLE_STRIP; case TRIANGLE_FAN: return GL_TRIANGLE_FAN; + case PATCHES: return GL_PATCHES; default: throw invalid_argument("get_gl_primitive_type"); } } diff --git a/source/backends/opengl/program_backend.cpp b/source/backends/opengl/program_backend.cpp index 398d35ce..3ebb7da1 100644 --- a/source/backends/opengl/program_backend.cpp +++ b/source/backends/opengl/program_backend.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -80,6 +81,8 @@ unsigned OpenGLProgram::add_stage(Stage type) switch(type) { case VERTEX: { static Require _req(ARB_vertex_shader); gl_type = GL_VERTEX_SHADER; } break; + case TESS_CONTROL: { static Require _req(ARB_tessellation_shader); gl_type = GL_TESS_CONTROL_SHADER; } break; + case TESS_EVAL: { static Require _req(ARB_tessellation_shader); gl_type = GL_TESS_EVALUATION_SHADER; } break; case GEOMETRY: { static Require _req(ARB_geometry_shader4); gl_type = GL_GEOMETRY_SHADER; } break; case FRAGMENT: { static Require _req(ARB_fragment_shader); gl_type = GL_FRAGMENT_SHADER; } break; case COMPUTE: { static Require _req(ARB_compute_shader); gl_type = GL_COMPUTE_SHADER; } break; @@ -123,6 +126,8 @@ void OpenGLProgram::add_glsl_stages(const GlslModule &mod, const mapis_compute()) pipeline_mask |= graphics_mask; @@ -177,9 +178,13 @@ void VulkanPipelineState::fill_graphics_creation_info(vector &buffer) cons ++n_color_attachments; } - StructureBuilder sb(buffer, 10); + bool has_tessellation = (self.shprog && self.shprog->has_tessellation()); + + StructureBuilder sb(buffer, 12); VkGraphicsPipelineCreateInfo *const &pipeline_info = sb.add(); VkPipelineInputAssemblyStateCreateInfo *const &input_assembly_info = sb.add(); + VkPipelineTessellationStateCreateInfo *const &tessellation_info = sb.add(has_tessellation); + VkPipelineTessellationDomainOriginStateCreateInfo *const &tess_origin_info = sb.add(has_tessellation); VkPipelineViewportStateCreateInfo *const &viewport_info = sb.add(); VkPipelineRasterizationStateCreateInfo *const &raster_info = sb.add(); VkPipelineMultisampleStateCreateInfo *const &multisample_info = sb.add(); @@ -191,7 +196,17 @@ void VulkanPipelineState::fill_graphics_creation_info(vector &buffer) cons input_assembly_info->sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; input_assembly_info->topology = static_cast(get_vulkan_primitive_type(self.primitive_type)); - input_assembly_info->primitiveRestartEnable = true; + input_assembly_info->primitiveRestartEnable = !has_tessellation; + + if(has_tessellation) + { + tessellation_info->sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO; + tessellation_info->pNext = tess_origin_info; + tessellation_info->patchControlPoints = self.patch_size; + + tess_origin_info->sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO; + tess_origin_info->domainOrigin = VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT; + } viewport_info->sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; viewport_info->viewportCount = 1; @@ -264,7 +279,7 @@ void VulkanPipelineState::fill_graphics_creation_info(vector &buffer) cons pipeline_info->sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; pipeline_info->pInputAssemblyState = input_assembly_info; - pipeline_info->pTessellationState = 0; + pipeline_info->pTessellationState = (has_tessellation ? tessellation_info : 0); pipeline_info->pViewportState = viewport_info; pipeline_info->pRasterizationState = raster_info; pipeline_info->pMultisampleState = multisample_info; diff --git a/source/backends/vulkan/primitivetype_backend.cpp b/source/backends/vulkan/primitivetype_backend.cpp index 4115af44..8538eadb 100644 --- a/source/backends/vulkan/primitivetype_backend.cpp +++ b/source/backends/vulkan/primitivetype_backend.cpp @@ -17,6 +17,7 @@ unsigned get_vulkan_primitive_type(PrimitiveType pt) case TRIANGLES: return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; case TRIANGLE_STRIP: return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; case TRIANGLE_FAN: return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN; + case PATCHES: return VK_PRIMITIVE_TOPOLOGY_PATCH_LIST; default: throw invalid_argument("get_vulkan_primitive_type"); } } diff --git a/source/backends/vulkan/program_backend.cpp b/source/backends/vulkan/program_backend.cpp index 993a3e38..10c04d83 100644 --- a/source/backends/vulkan/program_backend.cpp +++ b/source/backends/vulkan/program_backend.cpp @@ -180,6 +180,12 @@ bool VulkanProgram::is_compute() const return stage_flags&VK_SHADER_STAGE_COMPUTE_BIT; } +bool VulkanProgram::has_tessellation() const +{ + constexpr unsigned tess_flags = VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; + return (stage_flags&tess_flags)==tess_flags; +} + void VulkanProgram::set_debug_name(const string &name) { #ifdef DEBUG diff --git a/source/backends/vulkan/program_backend.h b/source/backends/vulkan/program_backend.h index 0e48b14b..654b19c7 100644 --- a/source/backends/vulkan/program_backend.h +++ b/source/backends/vulkan/program_backend.h @@ -36,6 +36,7 @@ protected: void finalize_uniforms(); bool is_compute() const; + bool has_tessellation() const; void set_debug_name(const std::string &); void set_vulkan_object_name() const; diff --git a/source/core/batch.cpp b/source/core/batch.cpp index c68beab9..83b7d49b 100644 --- a/source/core/batch.cpp +++ b/source/core/batch.cpp @@ -73,6 +73,16 @@ void Batch::set_index_type(DataType t) mark_dirty(); } +void Batch::set_patch_size(unsigned s) +{ + if(prim_type!=PATCHES) + throw invalid_operation("Batch::set_patch_size"); + if(s<1) + throw invalid_argument("Batch::set_patch_size"); + + patch_size = s; +} + Batch &Batch::append(unsigned i) { append_index(i); @@ -176,6 +186,7 @@ Batch::Loader::Loader(Batch &b): DataFile::ObjectLoader(b) { add("indices", &Loader::indices); + add("patch_size", &Loader::patch_size); } void Batch::Loader::indices(const vector &ind) @@ -183,5 +194,10 @@ void Batch::Loader::indices(const vector &ind) obj.append(ind); } +void Batch::Loader::patch_size(unsigned s) +{ + obj.set_patch_size(s); +} + } // namespace GL } // namespace Msp diff --git a/source/core/batch.h b/source/core/batch.h index 1fc22521..f3495860 100644 --- a/source/core/batch.h +++ b/source/core/batch.h @@ -30,6 +30,7 @@ public: Loader(Batch &); private: void indices(const std::vector &); + void patch_size(unsigned); }; private: @@ -37,6 +38,7 @@ private: DataType index_type; std::vector data; unsigned max_index; + unsigned patch_size = 3; public: Batch(PrimitiveType); @@ -50,6 +52,12 @@ public: DataType get_index_type() const { return index_type; } + /** Sets the number of control points per patch. Only available if the + primitive type is PATCHES. */ + void set_patch_size(unsigned); + + unsigned get_patch_size() const { return patch_size; } + /** Appends a single index. The data type is automatically adjusted if the index is too large for the current data type. */ Batch &append(unsigned); diff --git a/source/core/module.h b/source/core/module.h index 480a0669..4d151112 100644 --- a/source/core/module.h +++ b/source/core/module.h @@ -103,6 +103,8 @@ public: enum Stage { VERTEX = 0, + TESS_CONTROL = 1, + TESS_EVAL = 2, GEOMETRY = 3, FRAGMENT = 4, COMPUTE = 5 diff --git a/source/core/pipelinestate.cpp b/source/core/pipelinestate.cpp index 4dc54e24..0769d441 100644 --- a/source/core/pipelinestate.cpp +++ b/source/core/pipelinestate.cpp @@ -107,6 +107,11 @@ void PipelineState::set_primitive_type(PrimitiveType t) set(primitive_type, t, PRIMITIVE_TYPE); } +void PipelineState::set_patch_size(unsigned s) +{ + set(patch_size, s, PATCH_SIZE); +} + void PipelineState::set_front_face(FaceWinding w) { set(front_face, w, FACE_CULL); diff --git a/source/core/pipelinestate.h b/source/core/pipelinestate.h index 965bc15f..5156e0b5 100644 --- a/source/core/pipelinestate.h +++ b/source/core/pipelinestate.h @@ -73,7 +73,8 @@ private: DEPTH_TEST = 256, STENCIL_TEST = 512, BLEND = 1024, - PRIMITIVE_TYPE = 2048 + PRIMITIVE_TYPE = 2048, + PATCH_SIZE = 4096 }; const Framebuffer *framebuffer = 0; @@ -83,6 +84,7 @@ private: std::vector resources; const VertexSetup *vertex_setup = 0; PrimitiveType primitive_type = TRIANGLES; + unsigned patch_size = 0; FaceWinding front_face = COUNTERCLOCKWISE; CullMode face_cull = NO_CULL; DepthTest depth_test; @@ -105,6 +107,7 @@ private: public: void set_vertex_setup(const VertexSetup *); void set_primitive_type(PrimitiveType); + void set_patch_size(unsigned); void set_front_face(FaceWinding); void set_face_cull(CullMode); void set_depth_test(const DepthTest &); diff --git a/source/core/primitivetype.cpp b/source/core/primitivetype.cpp index 7698e2d6..ed4b1545 100644 --- a/source/core/primitivetype.cpp +++ b/source/core/primitivetype.cpp @@ -20,6 +20,8 @@ void operator>>(const LexicalConverter &conv, PrimitiveType &pt) pt = TRIANGLE_STRIP; else if(conv.get()=="TRIANGLE_FAN") pt = TRIANGLE_FAN; + else if(conv.get()=="PATCHES") + pt = PATCHES; else throw lexical_error(format("conversion of '%s' to PrimitiveType", conv.get())); } diff --git a/source/core/primitivetype.h b/source/core/primitivetype.h index 0c566f89..ae9be607 100644 --- a/source/core/primitivetype.h +++ b/source/core/primitivetype.h @@ -13,7 +13,8 @@ enum PrimitiveType LINE_STRIP, TRIANGLES, TRIANGLE_STRIP, - TRIANGLE_FAN + TRIANGLE_FAN, + PATCHES }; void operator>>(const LexicalConverter &, PrimitiveType &); diff --git a/source/core/program.h b/source/core/program.h index c652f468..3e206a70 100644 --- a/source/core/program.h +++ b/source/core/program.h @@ -73,6 +73,7 @@ private: public: using ProgramBackend::is_compute; + using ProgramBackend::has_tessellation; ReflectData::LayoutHash get_uniform_layout_hash() const { return reflect_data.layout_hash; } unsigned get_n_descriptor_sets() const { return reflect_data.n_descriptor_sets; } diff --git a/source/render/renderer.cpp b/source/render/renderer.cpp index aab37b67..352cf420 100644 --- a/source/render/renderer.cpp +++ b/source/render/renderer.cpp @@ -295,6 +295,8 @@ void Renderer::apply_batch(const Batch &batch) batch.refresh(frame_index); PipelineState &ps = get_pipeline_state(); ps.set_primitive_type(batch.get_type()); + if(batch.get_type()==PATCHES) + ps.set_patch_size(batch.get_patch_size()); commands.use_pipeline(&ps); }