Béziers on the GPU.
authorDavid Gow <david@ingeniumdigital.com>
Wed, 18 Jun 2014 15:36:27 +0000 (23:36 +0800)
committerDavid Gow <david@ingeniumdigital.com>
Wed, 18 Jun 2014 15:36:27 +0000 (23:36 +0800)
So this was a terrible thing in many ways.

What we're doing:
- Converting all of the coefficients to floats (+ doing a bit of
  preprocessing) and uploading the the GPU.
- Uploading the data_indices array from the document to the GPU.
- Using the vertex ids in the IBO when rendering béziers to get
  the object id, then looking up the data_indices array (as a texture)
  to find which bézier coefficients to use, then reading the bézier
  coefficients from another buffer texture and finally having the
  geometry shader generate 100 lines much as the CPU one does.

We're using buffer textures to access these things because they don't
have fixed sizes (and can get big), so we can't use uniform buffers and
because shader storage buffer objects need OpenGL 4.3, which only graphics
cards manufactured in the last 45 seconds actually support.

bin/ipdf
src/graphicsbuffer.cpp
src/graphicsbuffer.h
src/objectrenderer.cpp
src/objectrenderer.h
src/shaders/bezier_texbuf_geom.glsl [new file with mode: 0644]
src/shaders/rect_vert.glsl
src/view.cpp

index 412cf88..4739d21 100755 (executable)
Binary files a/bin/ipdf and b/bin/ipdf differ
index eb98450..576c2d6 100644 (file)
@@ -56,6 +56,8 @@ static GLenum BufferTypeToGLType(GraphicsBuffer::BufferType buffer_type)
                return GL_PIXEL_UNPACK_BUFFER;
        case GraphicsBuffer::BufferTypeUniform:
                return GL_UNIFORM_BUFFER;
+       case GraphicsBuffer::BufferTypeTexture:
+               return GL_TEXTURE_BUFFER;
        case GraphicsBuffer::BufferTypeDrawIndirect:
                return GL_DRAW_INDIRECT_BUFFER;
        default:
index 9513cb7..3dbb6fb 100644 (file)
@@ -20,6 +20,7 @@ namespace IPDF
                        BufferTypePixelPack,            // Pixel Pack buffer
                        BufferTypePixelUnpack,
                        BufferTypeUniform,              // Uniform/Constant buffer
+                       BufferTypeTexture,              // I was hoping to avoid this one.
                        BufferTypeDrawIndirect,
                };
                
@@ -54,6 +55,12 @@ namespace IPDF
                const size_t GetSize() const { return m_buffer_size; }
 
                void Invalidate();
+
+               // WARNING: The buffer handle can change for (almost) no reason.
+               // If you do _anything_ to the buffer, you'll need to call this
+               // again to see if we've recreated it in a vain attempt to outsmart
+               // the driver.
+               GLuint GetHandle() const { return m_buffer_handle; }
                
                void Bind() const;
        private:
index c552bd8..755df98 100644 (file)
@@ -251,6 +251,49 @@ void BezierRenderer::RenderUsingCPU(const Objects & objects, const View & view,
        }
 }
 
+void BezierRenderer::PrepareBezierGPUBuffer(const Objects& objects)
+{
+       m_bezier_coeffs.SetType(GraphicsBuffer::BufferTypeTexture);
+       m_bezier_coeffs.SetUsage(GraphicsBuffer::BufferUsageDynamicDraw);
+       m_bezier_coeffs.Resize(objects.beziers.size()*sizeof(GPUBezierCoeffs));
+       BufferBuilder<GPUBezierCoeffs> builder(m_bezier_coeffs.Map(false, true, true), m_bezier_coeffs.GetSize());
+
+       for (auto bez : objects.beziers)
+       {
+               GPUBezierCoeffs coeffs = {
+                       (float)bez.x0, (float)bez.y0,
+                       (float)bez.x1 - (float)bez.x0, (float)bez.y1 - (float)bez.y0,
+                       (float)bez.x2 - (float)bez.x0, (float)bez.y2 - (float)bez.y0
+                       };
+               builder.Add(coeffs);
+       }
+       m_bezier_coeffs.UnMap();
+       glGenTextures(1, &m_bezier_buffer_texture);
+       glBindTexture(GL_TEXTURE_BUFFER, m_bezier_buffer_texture);
+       glTexBuffer(GL_TEXTURE_BUFFER, GL_RG32F, m_bezier_coeffs.GetHandle());
+
+       m_bezier_ids.SetType(GraphicsBuffer::BufferTypeTexture);
+       m_bezier_ids.SetUsage(GraphicsBuffer::BufferUsageDynamicDraw);
+       m_bezier_ids.Upload(objects.data_indices.size() * sizeof(uint32_t), &objects.data_indices[0]);
+       
+       glGenTextures(1, &m_bezier_id_buffer_texture);
+       glActiveTexture(GL_TEXTURE1);
+       glBindTexture(GL_TEXTURE_BUFFER, m_bezier_id_buffer_texture);
+       glTexBuffer(GL_TEXTURE_BUFFER, GL_R32I, m_bezier_ids.GetHandle());
+       glActiveTexture(GL_TEXTURE0);
+}
+
+void BezierRenderer::RenderUsingGPU()
+{
+       if (!m_shader_program.Valid())
+               Warn("Shader is invalid (objects are of type %d)", m_type);
+       m_shader_program.Use();
+       glUniform1i(m_shader_program.GetUniformLocation("bezier_buffer_texture"), 0);
+       glUniform1i(m_shader_program.GetUniformLocation("bezier_id_buffer_texture"), 1);
+       m_ibo.Bind();
+       glDrawElements(GL_LINES, m_indexes.size()*2, GL_UNSIGNED_INT, 0);
+}
+
 /**
  * For debug, save pixels to bitmap
  */
index 4dd7fe1..4ebb66a 100644 (file)
@@ -108,14 +108,24 @@ namespace IPDF
        class BezierRenderer : public ObjectRenderer
        {
                public:
-                       BezierRenderer() : ObjectRenderer(BEZIER, "shaders/rect_vert.glsl", "shaders/rect_frag.glsl", "shaders/rect_outline_geom.glsl") {}
+                       BezierRenderer() : ObjectRenderer(BEZIER, "shaders/rect_vert.glsl", "shaders/rect_frag.glsl", "shaders/bezier_texbuf_geom.glsl") {}
                        virtual ~BezierRenderer() {}
-                       virtual void RenderUsingGPU() 
-                       {
-                               Error("Cannot render beziers on the GPU; they will appear as outlined rectangles.");    
-                               ObjectRenderer::RenderUsingGPU();
-                       }
+                       virtual void RenderUsingGPU(); 
                        virtual void RenderUsingCPU(const Objects & objects, const View & view, const CPURenderTarget & target);
+                       void PrepareBezierGPUBuffer(const Objects & objects);
+               private:
+                       GraphicsBuffer m_bezier_coeffs;
+                       GraphicsBuffer m_bezier_ids;
+                       struct GPUBezierCoeffs
+                       {
+                               float x0, y0;
+                               float x1, y1;
+                               float x2, y2;
+                       };
+
+                       GLuint m_bezier_buffer_texture;
+                       GLuint m_bezier_id_buffer_texture;
+
        };
 }
 
diff --git a/src/shaders/bezier_texbuf_geom.glsl b/src/shaders/bezier_texbuf_geom.glsl
new file mode 100644 (file)
index 0000000..2ee2836
--- /dev/null
@@ -0,0 +1,31 @@
+#version 150
+
+uniform samplerBuffer bezier_buffer_texture; 
+uniform isamplerBuffer bezier_id_buffer_texture; 
+
+layout(lines) in;
+layout(line_strip, max_vertices = 100) out;
+
+in int objectid[];
+
+void main()
+{
+       int bezierid = texelFetch(bezier_id_buffer_texture, objectid[0]).r;
+       vec2 boundssize = gl_in[1].gl_Position.xy - gl_in[0].gl_Position.xy;
+       vec2 coeff0 = texelFetch(bezier_buffer_texture, bezierid*3).rg + gl_in[0].gl_Position.xy ;
+       vec2 coeff1 = texelFetch(bezier_buffer_texture, bezierid*3+1).rg * boundssize + gl_in[0].gl_Position.xy;
+       vec2 coeff2 = texelFetch(bezier_buffer_texture, bezierid*3+2).rg * boundssize + gl_in[0].gl_Position.xy;
+       for (int i = 0; i <= 100; ++i)
+       {
+               float t = i * 0.01f;
+               float oneminust = 1.0f - t;
+               float bernstein0 = t*t;
+               float bernstein1 = 2*t*oneminust;
+               float bernstein2 = oneminust*oneminust;
+               gl_Position = vec4(coeff0*bernstein0 + coeff1*bernstein1 + coeff2*bernstein2, 0.0, 1.0);
+               EmitVertex();
+               
+       }
+       EndPrimitive();
+}
+
index cc15e56..a9f258a 100644 (file)
@@ -12,6 +12,8 @@ layout(std140, binding=0) uniform ViewBounds
 
 layout(location = 0) in vec2 position;
 
+out int objectid;
+
 void main()
 {
        vec2 transformed_position;
@@ -22,4 +24,6 @@ void main()
        gl_Position.y = 1 - (transformed_position.y*2);
        gl_Position.z = 0.0;
        gl_Position.w = 1.0;
+
+       objectid = gl_VertexID / 2;
 }
index cbcdbf4..4bba591 100644 (file)
@@ -288,6 +288,7 @@ void View::PrepareRender()
        for (unsigned i = 0; i < m_object_renderers.size(); ++i)
        {
                m_object_renderers[i]->FinaliseBuffers();
-       }       
+       }
+       dynamic_cast<BezierRenderer*>(m_object_renderers[BEZIER])->PrepareBezierGPUBuffer(m_document.m_objects);
        m_render_dirty = false;
 }

UCC git Repository :: git.ucc.asn.au