Changes.
[cairo/gpu.git] / src / gpu / cairo-gpu-impl-geometry-gl.h
blob87937a985bab172a35ba221dbfd7e605661d4211
1 /* the geometry context must always be bound before calling geometry_ functions */
3 /*
4 _cairo_gpu_geometry_begin
5 // write vertex data
6 _cairo_gpu_geometry_end
7 // draw
9 //optionally
11 // do something else
12 _cairo_gpu_bind
13 // draw again
15 _cairo_gpu_geometry_put
18 static inline cairo_gpu_geometry_t*
19 _cairo_gpu_geometry_init(cairo_gpu_geometry_t * geometry)
21 geometry->flags = 0;
22 geometry->vbo = 0;
23 geometry->vao = 0;
24 geometry->vbo_size = 0;
25 geometry->data = 0;
26 geometry->data_size = 0;
27 return geometry;
30 static inline cairo_gpu_geometry_t *
31 _cairo_gpu_geometry_fini_vbo(cairo_gpu_context_t * ctx, cairo_gpu_geometry_t * geometry)
33 if(geometry->vbo)
35 if(geometry->flags & GEOM_VBO_MAPPED)
36 ctx->gl.UnmapBufferARB(GL_ARRAY_BUFFER);
38 assert(ctx);
39 ctx->gl.DeleteBuffersARB(1, &geometry->vbo);
40 geometry->vbo = 0;
41 geometry->vbo_size = 0;
44 if(geometry->vao)
46 assert(ctx);
47 ctx->gl.DeleteVertexArrays(1, &geometry->vao);
48 geometry->vao = 0;
51 geometry->flags = 0;
52 return geometry;
56 static inline cairo_gpu_geometry_t *
57 _cairo_gpu_geometry_fini(cairo_gpu_context_t * ctx, cairo_gpu_geometry_t * geometry)
59 if(geometry->data)
61 free(geometry->data);
62 geometry->data = 0;
63 geometry->data_size = 0;
66 return _cairo_gpu_geometry_fini_vbo(ctx, geometry);
69 static void *
70 _cairo_gpu_geometry_begin(cairo_gpu_context_t * ctx, cairo_gpu_geometry_t * geometry, unsigned mode, int count, int vert, int color, int tex)
72 unsigned size = count * ((vert + !!color + tex) * sizeof(float));
74 _cairo_gpu_geometry_fini_vbo(ctx, geometry);
76 geometry->id = _cairo_id();
77 geometry->mode = mode;
78 geometry->vert = vert;
79 geometry->color = color;
80 geometry->tex = tex;
82 geometry->flags &=~ GEOM_SETUP;
84 assert(!(geometry->flags & GEOM_VBO_MAPPED));
86 // it seems VBOs are a win for large buffers, but a loss for small ones...
87 // TODO: maybe apply some threshold to use VBOs
88 if(ctx->space->use_vbo)
90 void *p = 0;
92 if(!geometry->vbo)
93 ctx->gl.GenBuffersARB(1, &geometry->vbo);
95 if(geometry->vbo)
97 if(geometry->id != ctx->vbo_id)
99 ctx->gl.BindBufferARB(GL_ARRAY_BUFFER, geometry->vbo);
100 ctx->vbo_id = geometry->id;
103 if(geometry->vbo_size < size)
105 if(!geometry->vbo_size)
106 geometry->vbo_size = 1;
107 while(geometry->vbo_size < size)
108 geometry->vbo_size <<= 1;
109 ctx->gl.BufferDataARB(GL_ARRAY_BUFFER, geometry->vbo_size, 0, GL_STREAM_DRAW);
112 #ifdef GLEW_ARB_map_buffer_range
113 if(GLEW_ARB_map_buffer_range)
114 p = ctx->gl.MapBufferRange(GL_ARRAY_BUFFER, 0, size, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
115 else
116 #endif
117 p = ctx->gl.MapBufferARB(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
120 if(p)
122 geometry->flags |= GEOM_VBO_MAPPED;
123 return p;
125 else
127 fprintf(stderr, "vbo create/map failed for %i! fallback!\n", size);
131 if(geometry->data_size < size)
133 if(!geometry->data_size)
134 geometry->data_size = 1;
135 while(geometry->data_size < size)
136 geometry->data_size <<= 1;
137 if(geometry->data)
138 free(geometry->data);
140 geometry->data = malloc(geometry->data_size);
143 return geometry->data;
146 static void
147 _cairo_gpu_geometry_end(cairo_gpu_context_t * ctx, cairo_gpu_geometry_t * geometry, int count)
149 int size = count * ((geometry->vert + geometry->tex + !!geometry->color) * sizeof(float));
151 geometry->count = count;
152 if(geometry->vbo)
154 if(geometry->id != ctx->vbo_id)
156 ctx->gl.BindBufferARB(GL_ARRAY_BUFFER, (unsigned)geometry->vbo);
157 ctx->vbo_id = geometry->id;
160 if(geometry->flags & GEOM_VBO_MAPPED)
162 ctx->gl.UnmapBufferARB(GL_ARRAY_BUFFER);
163 geometry->flags &= ~GEOM_VBO_MAPPED;
165 else if(size)
166 ctx->gl.BufferDataARB(GL_ARRAY_BUFFER, size, geometry->data, GL_STREAM_DRAW);
170 static inline void
171 _cairo_gpu_geometry__do_bind(cairo_gpu_context_t * ctx, cairo_gpu_geometry_t* geometry)
173 char* base;
174 GLsizei stride;
175 int vert = geometry->vert;
176 int tex = geometry->tex;
177 int color = geometry->color;
179 // XXX: fix and reenable VAO support
180 //if(0 && !geometry->vao && GLEW_ARB_vertex_array_object)
181 if(0)
183 ctx->gl.GenVertexArrays(1, &geometry->vao);
184 if(geometry->vao)
186 ctx->gl.BindVertexArray(geometry->vao);
187 ctx->vao_id = geometry->id;
191 if(geometry->id != ctx->vbo_id)
193 ctx->gl.BindBufferARB(GL_ARRAY_BUFFER, (unsigned)geometry->vbo);
194 ctx->vbo_id = geometry->id;
197 if(geometry->vbo)
198 base = 0;
199 else
200 base = (char *)geometry->data;
202 stride = (vert + !!color + tex) * sizeof(float);
203 if(vert)
205 ctx->gl.VertexPointer(vert, GL_FLOAT, stride, base);
206 if(!ctx->vertex_array)
208 ctx->gl.EnableClientState(GL_VERTEX_ARRAY);
209 ctx->vertex_array = 1;
212 else
214 if(ctx->vertex_array)
216 ctx->gl.DisableClientState(GL_VERTEX_ARRAY);
217 ctx->vertex_array = 0;
221 if(color)
223 ctx->gl.ColorPointer(color, GL_UNSIGNED_BYTE, stride, base + vert * sizeof(float));
224 if(!ctx->color_array)
226 ctx->gl.EnableClientState(GL_COLOR_ARRAY);
227 ctx->color_array = 1;
230 else
232 if(ctx->color_array)
234 ctx->gl.DisableClientState(GL_COLOR_ARRAY);
235 ctx->color_array = 0;
239 // TODO: this is an hack for show_glyphs, we should maybe do it more generally?
240 if(tex)
242 ctx->gl.ClientActiveTextureARB(GL_TEXTURE0);
243 ctx->gl.TexCoordPointer(tex, GL_FLOAT, stride, base + (vert + !!color) * sizeof(float));
244 if(!ctx->tex_array)
245 ctx->gl.EnableClientState(GL_TEXTURE_COORD_ARRAY);
246 ctx->gl.ClientActiveTextureARB(GL_TEXTURE1);
247 ctx->gl.TexCoordPointer(tex, GL_FLOAT, stride, base + (vert + !!color) * sizeof(float));
248 if(!ctx->tex_array)
250 ctx->gl.EnableClientState(GL_TEXTURE_COORD_ARRAY);
251 ctx->tex_array = 1;
254 else
256 if(ctx->tex_array)
258 ctx->gl.ClientActiveTextureARB(GL_TEXTURE0);
259 ctx->gl.DisableClientState(GL_TEXTURE_COORD_ARRAY);
260 ctx->gl.ClientActiveTextureARB(GL_TEXTURE1);
261 ctx->gl.DisableClientState(GL_TEXTURE_COORD_ARRAY);
262 ctx->tex_array = 0;
267 static inline void
268 _cairo_gpu_geometry_bind(cairo_gpu_context_t * ctx, cairo_gpu_geometry_t * geometry)
270 if(geometry->vao)
272 if(ctx->vao_id != geometry->id)
274 ctx->gl.BindVertexArray(geometry->vao);
275 ctx->vao_id = geometry->id;
278 else
280 if(ctx->vao_id)
282 ctx->gl.BindVertexArray(0);
283 ctx->vao_id = 0;
286 if(ctx->vao0_id != geometry->id)
288 geometry->flags &= ~GEOM_SETUP;
289 ctx->vao0_id = geometry->id;
293 ctx->mode = geometry->mode;
294 ctx->count = geometry->count;
296 if(geometry->flags & GEOM_SETUP)
297 return;
299 _cairo_gpu_geometry__do_bind(ctx, geometry);
302 #if 0
303 static inline void
304 _cairo_gpu_geometry_put(cairo_gpu_context_t * ctx, cairo_gpu_geometry_t * geometry)
306 if(geometry->vbo && (geometry->vbo_size > 256 * 1024))
308 if(geometry->vbo != ctx->vbo)
310 ctx->gl.BindBufferARB(GL_ARRAY_BUFFER, (unsigned)geometry->vbo);
311 ctx->vbo = geometry->vbo;
314 // this seems to sometimes fail on nVidia (why?!)
315 ctx->gl.BufferDataARB(GL_ARRAY_BUFFER, 0, 0, GL_STREAM_DRAW);
316 while(ctx->gl.GetError())
319 geometry->vbo_size = 0;
322 #endif
325 static inline cairo_geometry_t*
326 _cairo_gpu_space_create_geometry(cairo_gpu_space_t* space)
328 cairo_gpu_user_geometry_t* geometry = (cairo_gpu_geometry_t*)malloc(sizeof(cairo_gpu_user_geometry_t));
329 geometry->space = space;
330 _cairo_gpu_geometry_init(&geometry->geometry, space);
331 return &geometry->base;
334 static inline void
335 _cairo_gpu_geometry_destroy(cairo_gpu_user_geometry_t* geometry)
337 cairo_gpu_context_t* ctx = cairo_space_bind(geometry->space);
338 _cairo_gpu_geometry_fini(ctx, &geometry->geometry);
339 free(geometry);