Rev 4358 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4358 | Serge | 1 | /* |
2 | * Copyright (c) 2013 Brian Paul All Rights Reserved. |
||
3 | * |
||
4 | * Permission is hereby granted, free of charge, to any person obtaining a |
||
5 | * copy of this software and associated documentation files (the "Software"), |
||
6 | * to deal in the Software without restriction, including without limitation |
||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||
8 | * and/or sell copies of the Software, and to permit persons to whom the |
||
9 | * Software is furnished to do so, subject to the following conditions: |
||
10 | * |
||
11 | * The above copyright notice and this permission notice shall be included |
||
12 | * in all copies or substantial portions of the Software. |
||
13 | * |
||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
||
15 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||
17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR |
||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
||
20 | * OTHER DEALINGS IN THE SOFTWARE. |
||
21 | */ |
||
22 | |||
23 | |||
24 | /* |
||
25 | * Off-Screen rendering into client memory. |
||
26 | * State tracker for gallium (for softpipe and llvmpipe) |
||
27 | * |
||
28 | * Notes: |
||
29 | * |
||
30 | * If Gallium is built with LLVM support we use the llvmpipe driver. |
||
31 | * Otherwise we use softpipe. The GALLIUM_DRIVER environment variable |
||
32 | * may be set to "softpipe" or "llvmpipe" to override. |
||
33 | * |
||
34 | * With softpipe we could render directly into the user's buffer by using a |
||
35 | * display target resource. However, softpipe doesn't suport "upside-down" |
||
36 | * rendering which would be needed for the OSMESA_Y_UP=TRUE case. |
||
37 | * |
||
38 | * With llvmpipe we could only render directly into the user's buffer when its |
||
39 | * width and height is a multiple of the tile size (64 pixels). |
||
40 | * |
||
41 | * Because of these constraints we always render into ordinary resources then |
||
42 | * copy the results to the user's buffer in the flush_front() function which |
||
43 | * is called when the app calls glFlush/Finish. |
||
44 | * |
||
45 | * In general, the OSMesa interface is pretty ugly and not a good match |
||
46 | * for Gallium. But we're interested in doing the best we can to preserve |
||
47 | * application portability. With a little work we could come up with a |
||
48 | * much nicer, new off-screen Gallium interface... |
||
49 | */ |
||
50 | |||
51 | |||
52 | #include "GL/osmesa.h" |
||
53 | |||
54 | #include "glapi/glapi.h" /* for OSMesaGetProcAddress below */ |
||
55 | |||
56 | #include "pipe/p_context.h" |
||
57 | #include "pipe/p_screen.h" |
||
58 | #include "pipe/p_state.h" |
||
59 | |||
60 | #include "util/u_atomic.h" |
||
61 | #include "util/u_box.h" |
||
62 | #include "util/u_format.h" |
||
63 | #include "util/u_memory.h" |
||
64 | |||
65 | #include "state_tracker/st_api.h" |
||
66 | #include "state_tracker/st_gl_api.h" |
||
67 | |||
68 | |||
69 | |||
70 | extern struct pipe_screen * |
||
71 | osmesa_create_screen(void); |
||
72 | |||
73 | |||
74 | |||
75 | struct osmesa_buffer |
||
76 | { |
||
77 | struct st_framebuffer_iface *stfb; |
||
78 | struct st_visual visual; |
||
79 | unsigned width, height; |
||
80 | |||
81 | struct pipe_resource *textures[ST_ATTACHMENT_COUNT]; |
||
82 | |||
83 | void *map; |
||
84 | |||
85 | struct osmesa_buffer *next; /**< next in linked list */ |
||
86 | }; |
||
87 | |||
88 | |||
89 | struct osmesa_context |
||
90 | { |
||
91 | struct st_context_iface *stctx; |
||
92 | |||
93 | struct osmesa_buffer *current_buffer; |
||
94 | |||
95 | enum pipe_format depth_stencil_format, accum_format; |
||
96 | |||
97 | GLenum format; /*< User-specified context format */ |
||
98 | GLenum type; /*< Buffer's data type */ |
||
99 | GLint user_row_length; /*< user-specified number of pixels per row */ |
||
100 | GLboolean y_up; /*< TRUE -> Y increases upward */ |
||
101 | /*< FALSE -> Y increases downward */ |
||
102 | }; |
||
103 | |||
104 | |||
105 | /** |
||
106 | * Linked list of all osmesa_buffers. |
||
107 | * We can re-use an osmesa_buffer from one OSMesaMakeCurrent() call to |
||
108 | * the next unless the color/depth/stencil/accum formats change. |
||
109 | * We have to do this to be compatible with the original OSMesa implementation |
||
110 | * because some apps call OSMesaMakeCurrent() several times during rendering |
||
111 | * a frame. |
||
112 | */ |
||
113 | static struct osmesa_buffer *BufferList = NULL; |
||
114 | |||
115 | |||
116 | /** |
||
117 | * Called from the ST manager. |
||
118 | */ |
||
119 | static int |
||
120 | osmesa_st_get_param(struct st_manager *smapi, enum st_manager_param param) |
||
121 | { |
||
122 | /* no-op */ |
||
123 | return 0; |
||
124 | } |
||
125 | |||
126 | |||
127 | /** |
||
128 | * Create/return singleton st_api object. |
||
129 | */ |
||
130 | static struct st_api * |
||
131 | get_st_api(void) |
||
132 | { |
||
133 | static struct st_api *stapi = NULL; |
||
134 | if (!stapi) { |
||
135 | stapi = st_gl_api_create(); |
||
136 | } |
||
137 | return stapi; |
||
138 | } |
||
139 | |||
140 | |||
141 | /** |
||
142 | * Create/return a singleton st_manager object. |
||
143 | */ |
||
144 | static struct st_manager * |
||
145 | get_st_manager(void) |
||
146 | { |
||
147 | static struct st_manager *stmgr = NULL; |
||
148 | if (!stmgr) { |
||
149 | stmgr = CALLOC_STRUCT(st_manager); |
||
150 | if (stmgr) { |
||
151 | stmgr->screen = osmesa_create_screen(); |
||
152 | stmgr->get_param = osmesa_st_get_param; |
||
153 | stmgr->get_egl_image = NULL; |
||
5063 | serge | 154 | } |
4358 | Serge | 155 | } |
156 | return stmgr; |
||
157 | } |
||
158 | |||
159 | |||
160 | static INLINE boolean |
||
161 | little_endian(void) |
||
162 | { |
||
163 | const unsigned ui = 1; |
||
164 | return *((const char *) &ui); |
||
165 | } |
||
166 | |||
167 | |||
168 | /** |
||
169 | * Given an OSMESA_x format and a GL_y type, return the best |
||
170 | * matching PIPE_FORMAT_z. |
||
171 | * Note that we can't exactly match all user format/type combinations |
||
172 | * with gallium formats. If we find this to be a problem, we can |
||
173 | * implement more elaborate format/type conversion in the flush_front() |
||
174 | * function. |
||
175 | */ |
||
176 | static enum pipe_format |
||
177 | osmesa_choose_format(GLenum format, GLenum type) |
||
178 | { |
||
179 | switch (format) { |
||
180 | case OSMESA_RGBA: |
||
181 | if (type == GL_UNSIGNED_BYTE) { |
||
182 | if (little_endian()) |
||
183 | return PIPE_FORMAT_R8G8B8A8_UNORM; |
||
184 | else |
||
185 | return PIPE_FORMAT_A8B8G8R8_UNORM; |
||
186 | } |
||
187 | else if (type == GL_UNSIGNED_SHORT) { |
||
188 | return PIPE_FORMAT_R16G16B16A16_UNORM; |
||
189 | } |
||
190 | else if (type == GL_FLOAT) { |
||
191 | return PIPE_FORMAT_R32G32B32A32_FLOAT; |
||
192 | } |
||
193 | else { |
||
194 | return PIPE_FORMAT_NONE; |
||
195 | } |
||
196 | break; |
||
197 | case OSMESA_BGRA: |
||
198 | if (type == GL_UNSIGNED_BYTE) { |
||
199 | if (little_endian()) |
||
200 | return PIPE_FORMAT_B8G8R8A8_UNORM; |
||
201 | else |
||
202 | return PIPE_FORMAT_A8R8G8B8_UNORM; |
||
203 | } |
||
204 | else if (type == GL_UNSIGNED_SHORT) { |
||
205 | return PIPE_FORMAT_R16G16B16A16_UNORM; |
||
206 | } |
||
207 | else if (type == GL_FLOAT) { |
||
208 | return PIPE_FORMAT_R32G32B32A32_FLOAT; |
||
209 | } |
||
210 | else { |
||
211 | return PIPE_FORMAT_NONE; |
||
212 | } |
||
213 | break; |
||
214 | case OSMESA_ARGB: |
||
215 | if (type == GL_UNSIGNED_BYTE) { |
||
216 | if (little_endian()) |
||
217 | return PIPE_FORMAT_A8R8G8B8_UNORM; |
||
218 | else |
||
219 | return PIPE_FORMAT_B8G8R8A8_UNORM; |
||
220 | } |
||
221 | else if (type == GL_UNSIGNED_SHORT) { |
||
222 | return PIPE_FORMAT_R16G16B16A16_UNORM; |
||
223 | } |
||
224 | else if (type == GL_FLOAT) { |
||
225 | return PIPE_FORMAT_R32G32B32A32_FLOAT; |
||
226 | } |
||
227 | else { |
||
228 | return PIPE_FORMAT_NONE; |
||
229 | } |
||
230 | break; |
||
231 | case OSMESA_RGB: |
||
232 | if (type == GL_UNSIGNED_BYTE) { |
||
233 | return PIPE_FORMAT_R8G8B8_UNORM; |
||
234 | } |
||
235 | else if (type == GL_UNSIGNED_SHORT) { |
||
236 | return PIPE_FORMAT_R16G16B16_UNORM; |
||
237 | } |
||
238 | else if (type == GL_FLOAT) { |
||
239 | return PIPE_FORMAT_R32G32B32_FLOAT; |
||
240 | } |
||
241 | else { |
||
242 | return PIPE_FORMAT_NONE; |
||
243 | } |
||
244 | break; |
||
245 | case OSMESA_BGR: |
||
246 | /* No gallium format for this one */ |
||
247 | return PIPE_FORMAT_NONE; |
||
248 | case OSMESA_RGB_565: |
||
249 | return PIPE_FORMAT_B5G6R5_UNORM; |
||
250 | default: |
||
251 | ; /* fall-through */ |
||
252 | } |
||
253 | return PIPE_FORMAT_NONE; |
||
254 | } |
||
255 | |||
256 | |||
257 | /** |
||
258 | * Initialize an st_visual object. |
||
259 | */ |
||
260 | static void |
||
261 | osmesa_init_st_visual(struct st_visual *vis, |
||
262 | enum pipe_format color_format, |
||
263 | enum pipe_format ds_format, |
||
264 | enum pipe_format accum_format) |
||
265 | { |
||
266 | vis->buffer_mask = ST_ATTACHMENT_FRONT_LEFT_MASK; |
||
267 | vis->color_format = color_format; |
||
268 | vis->depth_stencil_format = ds_format; |
||
269 | vis->accum_format = accum_format; |
||
270 | vis->samples = 1; |
||
271 | vis->render_buffer = ST_ATTACHMENT_FRONT_LEFT; |
||
272 | } |
||
273 | |||
274 | |||
275 | /** |
||
276 | * Return the osmesa_buffer that corresponds to an st_framebuffer_iface. |
||
277 | */ |
||
278 | static INLINE struct osmesa_buffer * |
||
279 | stfbi_to_osbuffer(struct st_framebuffer_iface *stfbi) |
||
280 | { |
||
281 | return (struct osmesa_buffer *) stfbi->st_manager_private; |
||
282 | } |
||
283 | |||
284 | |||
285 | /** |
||
286 | * Called via glFlush/glFinish. This is where we copy the contents |
||
287 | * of the driver's color buffer into the user-specified buffer. |
||
288 | */ |
||
289 | static boolean |
||
290 | osmesa_st_framebuffer_flush_front(struct st_context_iface *stctx, |
||
291 | struct st_framebuffer_iface *stfbi, |
||
292 | enum st_attachment_type statt) |
||
293 | { |
||
294 | OSMesaContext osmesa = OSMesaGetCurrentContext(); |
||
295 | struct osmesa_buffer *osbuffer = stfbi_to_osbuffer(stfbi); |
||
296 | struct pipe_context *pipe = stctx->pipe; |
||
297 | struct pipe_resource *res = osbuffer->textures[statt]; |
||
298 | struct pipe_transfer *transfer = NULL; |
||
299 | struct pipe_box box; |
||
300 | void *map; |
||
301 | ubyte *src, *dst; |
||
302 | unsigned y, bytes, bpp; |
||
303 | int dst_stride; |
||
304 | |||
305 | u_box_2d(0, 0, res->width0, res->height0, &box); |
||
306 | |||
307 | map = pipe->transfer_map(pipe, res, 0, PIPE_TRANSFER_READ, &box, |
||
308 | &transfer); |
||
309 | |||
310 | /* |
||
311 | * Copy the color buffer from the resource to the user's buffer. |
||
312 | */ |
||
313 | bpp = util_format_get_blocksize(osbuffer->visual.color_format); |
||
314 | src = map; |
||
315 | dst = osbuffer->map; |
||
316 | if (osmesa->user_row_length) |
||
317 | dst_stride = bpp * osmesa->user_row_length; |
||
318 | else |
||
319 | dst_stride = bpp * osbuffer->width; |
||
320 | bytes = bpp * res->width0; |
||
321 | |||
322 | if (osmesa->y_up) { |
||
323 | /* need to flip image upside down */ |
||
324 | dst = dst + (res->height0 - 1) * dst_stride; |
||
325 | dst_stride = -dst_stride; |
||
326 | } |
||
327 | |||
328 | for (y = 0; y < res->height0; y++) { |
||
329 | memcpy(dst, src, bytes); |
||
330 | dst += dst_stride; |
||
331 | src += transfer->stride; |
||
332 | } |
||
333 | |||
334 | pipe->transfer_unmap(pipe, transfer); |
||
335 | |||
336 | return TRUE; |
||
337 | } |
||
338 | |||
339 | |||
340 | /** |
||
341 | * Called by the st manager to validate the framebuffer (allocate |
||
342 | * its resources). |
||
343 | */ |
||
344 | static boolean |
||
345 | osmesa_st_framebuffer_validate(struct st_context_iface *stctx, |
||
346 | struct st_framebuffer_iface *stfbi, |
||
347 | const enum st_attachment_type *statts, |
||
348 | unsigned count, |
||
349 | struct pipe_resource **out) |
||
350 | { |
||
351 | struct pipe_screen *screen = get_st_manager()->screen; |
||
352 | enum st_attachment_type i; |
||
353 | struct osmesa_buffer *osbuffer = stfbi_to_osbuffer(stfbi); |
||
354 | struct pipe_resource templat; |
||
355 | |||
356 | memset(&templat, 0, sizeof(templat)); |
||
357 | templat.target = PIPE_TEXTURE_RECT; |
||
358 | templat.format = 0; /* setup below */ |
||
359 | templat.last_level = 0; |
||
360 | templat.width0 = osbuffer->width; |
||
361 | templat.height0 = osbuffer->height; |
||
362 | templat.depth0 = 1; |
||
363 | templat.array_size = 1; |
||
364 | templat.usage = PIPE_USAGE_DEFAULT; |
||
365 | templat.bind = 0; /* setup below */ |
||
366 | templat.flags = 0; |
||
367 | |||
368 | for (i = 0; i < count; i++) { |
||
369 | enum pipe_format format = PIPE_FORMAT_NONE; |
||
370 | unsigned bind = 0; |
||
371 | |||
372 | /* |
||
373 | * At this time, we really only need to handle the front-left color |
||
374 | * attachment, since that's all we specified for the visual in |
||
375 | * osmesa_init_st_visual(). |
||
376 | */ |
||
377 | if (statts[i] == ST_ATTACHMENT_FRONT_LEFT) { |
||
378 | format = osbuffer->visual.color_format; |
||
379 | bind = PIPE_BIND_RENDER_TARGET; |
||
380 | } |
||
381 | else if (statts[i] == ST_ATTACHMENT_DEPTH_STENCIL) { |
||
382 | format = osbuffer->visual.depth_stencil_format; |
||
383 | bind = PIPE_BIND_DEPTH_STENCIL; |
||
384 | } |
||
385 | else if (statts[i] == ST_ATTACHMENT_ACCUM) { |
||
386 | format = osbuffer->visual.accum_format; |
||
387 | bind = PIPE_BIND_RENDER_TARGET; |
||
388 | } |
||
389 | else { |
||
390 | debug_warning("Unexpected attachment type in " |
||
391 | "osmesa_st_framebuffer_validate()"); |
||
392 | } |
||
393 | |||
394 | templat.format = format; |
||
395 | templat.bind = bind; |
||
396 | out[i] = osbuffer->textures[i] = |
||
397 | screen->resource_create(screen, &templat); |
||
398 | } |
||
399 | |||
400 | return TRUE; |
||
401 | } |
||
402 | |||
403 | |||
404 | static struct st_framebuffer_iface * |
||
405 | osmesa_create_st_framebuffer(void) |
||
406 | { |
||
407 | struct st_framebuffer_iface *stfbi = CALLOC_STRUCT(st_framebuffer_iface); |
||
408 | if (stfbi) { |
||
409 | stfbi->flush_front = osmesa_st_framebuffer_flush_front; |
||
410 | stfbi->validate = osmesa_st_framebuffer_validate; |
||
411 | p_atomic_set(&stfbi->stamp, 1); |
||
412 | } |
||
413 | return stfbi; |
||
414 | } |
||
415 | |||
416 | |||
417 | /** |
||
418 | * Create new buffer and add to linked list. |
||
419 | */ |
||
420 | static struct osmesa_buffer * |
||
421 | osmesa_create_buffer(enum pipe_format color_format, |
||
422 | enum pipe_format ds_format, |
||
423 | enum pipe_format accum_format) |
||
424 | { |
||
425 | struct osmesa_buffer *osbuffer = CALLOC_STRUCT(osmesa_buffer); |
||
426 | if (osbuffer) { |
||
427 | osbuffer->stfb = osmesa_create_st_framebuffer(); |
||
428 | |||
429 | osbuffer->stfb->st_manager_private = osbuffer; |
||
430 | osbuffer->stfb->visual = &osbuffer->visual; |
||
431 | |||
432 | osmesa_init_st_visual(&osbuffer->visual, color_format, |
||
433 | ds_format, accum_format); |
||
434 | |||
435 | /* insert into linked list */ |
||
436 | osbuffer->next = BufferList; |
||
437 | BufferList = osbuffer; |
||
438 | } |
||
439 | |||
440 | return osbuffer; |
||
441 | } |
||
442 | |||
443 | |||
444 | /** |
||
445 | * Search linked list for a buffer with matching pixel formats. |
||
446 | */ |
||
447 | static struct osmesa_buffer * |
||
448 | osmesa_find_buffer(enum pipe_format color_format, |
||
449 | enum pipe_format ds_format, |
||
450 | enum pipe_format accum_format) |
||
451 | { |
||
452 | struct osmesa_buffer *b; |
||
453 | |||
454 | /* Check if we already have a suitable buffer for the given formats */ |
||
455 | for (b = BufferList; b; b = b->next) { |
||
456 | if (b->visual.color_format == color_format && |
||
457 | b->visual.depth_stencil_format == ds_format && |
||
458 | b->visual.accum_format == accum_format) { |
||
459 | return b; |
||
460 | } |
||
461 | } |
||
462 | return NULL; |
||
463 | } |
||
464 | |||
465 | |||
466 | static void |
||
467 | osmesa_destroy_buffer(struct osmesa_buffer *osbuffer) |
||
468 | { |
||
469 | FREE(osbuffer->stfb); |
||
470 | FREE(osbuffer); |
||
471 | } |
||
472 | |||
473 | |||
474 | |||
475 | /**********************************************************************/ |
||
476 | /***** Public Functions *****/ |
||
477 | /**********************************************************************/ |
||
478 | |||
479 | |||
480 | /** |
||
481 | * Create an Off-Screen Mesa rendering context. The only attribute needed is |
||
482 | * an RGBA vs Color-Index mode flag. |
||
483 | * |
||
484 | * Input: format - Must be GL_RGBA |
||
485 | * sharelist - specifies another OSMesaContext with which to share |
||
486 | * display lists. NULL indicates no sharing. |
||
487 | * Return: an OSMesaContext or 0 if error |
||
488 | */ |
||
489 | GLAPI OSMesaContext GLAPIENTRY |
||
490 | OSMesaCreateContext(GLenum format, OSMesaContext sharelist) |
||
491 | { |
||
492 | return OSMesaCreateContextExt(format, 24, 8, 0, sharelist); |
||
493 | } |
||
494 | |||
495 | |||
496 | /** |
||
497 | * New in Mesa 3.5 |
||
498 | * |
||
499 | * Create context and specify size of ancillary buffers. |
||
500 | */ |
||
501 | GLAPI OSMesaContext GLAPIENTRY |
||
502 | OSMesaCreateContextExt(GLenum format, GLint depthBits, GLint stencilBits, |
||
503 | GLint accumBits, OSMesaContext sharelist) |
||
504 | { |
||
505 | OSMesaContext osmesa; |
||
506 | struct st_context_iface *st_shared; |
||
507 | enum st_context_error st_error = 0; |
||
508 | struct st_context_attribs attribs; |
||
509 | struct st_api *stapi = get_st_api(); |
||
510 | |||
511 | if (sharelist) { |
||
512 | st_shared = sharelist->stctx; |
||
513 | } |
||
514 | else { |
||
515 | st_shared = NULL; |
||
516 | } |
||
517 | |||
518 | osmesa = (OSMesaContext) CALLOC_STRUCT(osmesa_context); |
||
519 | if (!osmesa) |
||
520 | return NULL; |
||
521 | |||
522 | /* Choose depth/stencil/accum buffer formats */ |
||
523 | if (accumBits > 0) { |
||
524 | osmesa->accum_format = PIPE_FORMAT_R16G16B16A16_SNORM; |
||
525 | } |
||
526 | if (depthBits > 0 && stencilBits > 0) { |
||
527 | osmesa->depth_stencil_format = PIPE_FORMAT_Z24_UNORM_S8_UINT; |
||
528 | } |
||
529 | else if (stencilBits > 0) { |
||
530 | osmesa->depth_stencil_format = PIPE_FORMAT_S8_UINT; |
||
531 | } |
||
532 | else if (depthBits >= 24) { |
||
533 | osmesa->depth_stencil_format = PIPE_FORMAT_Z24X8_UNORM; |
||
534 | } |
||
535 | else if (depthBits >= 16) { |
||
536 | osmesa->depth_stencil_format = PIPE_FORMAT_Z16_UNORM; |
||
537 | } |
||
538 | |||
539 | /* |
||
540 | * Create the rendering context |
||
541 | */ |
||
542 | attribs.profile = ST_PROFILE_DEFAULT; |
||
543 | attribs.major = 2; |
||
544 | attribs.minor = 1; |
||
545 | attribs.flags = 0; /* ST_CONTEXT_FLAG_x */ |
||
546 | attribs.options.force_glsl_extensions_warn = FALSE; |
||
547 | attribs.options.disable_blend_func_extended = FALSE; |
||
548 | attribs.options.disable_glsl_line_continuations = FALSE; |
||
549 | attribs.options.disable_shader_bit_encoding = FALSE; |
||
550 | attribs.options.force_s3tc_enable = FALSE; |
||
551 | attribs.options.force_glsl_version = 0; |
||
552 | |||
553 | osmesa_init_st_visual(&attribs.visual, |
||
554 | PIPE_FORMAT_R8G8B8A8_UNORM, |
||
555 | osmesa->depth_stencil_format, |
||
556 | osmesa->accum_format); |
||
557 | |||
558 | osmesa->stctx = stapi->create_context(stapi, get_st_manager(), |
||
559 | &attribs, &st_error, st_shared); |
||
560 | if (!osmesa->stctx) { |
||
561 | FREE(osmesa); |
||
562 | return NULL; |
||
563 | } |
||
564 | |||
565 | osmesa->stctx->st_manager_private = osmesa; |
||
566 | |||
567 | osmesa->format = format; |
||
568 | osmesa->user_row_length = 0; |
||
569 | osmesa->y_up = GL_TRUE; |
||
570 | |||
571 | return osmesa; |
||
572 | } |
||
573 | |||
574 | |||
575 | /** |
||
576 | * Destroy an Off-Screen Mesa rendering context. |
||
577 | * |
||
578 | * \param osmesa the context to destroy |
||
579 | */ |
||
580 | GLAPI void GLAPIENTRY |
||
581 | OSMesaDestroyContext(OSMesaContext osmesa) |
||
582 | { |
||
583 | if (osmesa) { |
||
584 | osmesa->stctx->destroy(osmesa->stctx); |
||
585 | FREE(osmesa); |
||
586 | } |
||
587 | } |
||
588 | |||
589 | |||
590 | /** |
||
591 | * Bind an OSMesaContext to an image buffer. The image buffer is just a |
||
592 | * block of memory which the client provides. Its size must be at least |
||
593 | * as large as width*height*pixelSize. Its address should be a multiple |
||
594 | * of 4 if using RGBA mode. |
||
595 | * |
||
596 | * By default, image data is stored in the order of glDrawPixels: row-major |
||
597 | * order with the lower-left image pixel stored in the first array position |
||
598 | * (ie. bottom-to-top). |
||
599 | * |
||
600 | * If the context's viewport hasn't been initialized yet, it will now be |
||
601 | * initialized to (0,0,width,height). |
||
602 | * |
||
603 | * Input: osmesa - the rendering context |
||
604 | * buffer - the image buffer memory |
||
605 | * type - data type for pixel components |
||
606 | * GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_SHORT |
||
607 | * or GL_FLOAT. |
||
608 | * width, height - size of image buffer in pixels, at least 1 |
||
609 | * Return: GL_TRUE if success, GL_FALSE if error because of invalid osmesa, |
||
610 | * invalid type, invalid size, etc. |
||
611 | */ |
||
612 | GLAPI GLboolean GLAPIENTRY |
||
613 | OSMesaMakeCurrent(OSMesaContext osmesa, void *buffer, GLenum type, |
||
614 | GLsizei width, GLsizei height) |
||
615 | { |
||
616 | struct st_api *stapi = get_st_api(); |
||
617 | struct osmesa_buffer *osbuffer; |
||
618 | enum pipe_format color_format; |
||
619 | |||
620 | if (!osmesa || !buffer || width < 1 || height < 1) { |
||
621 | return GL_FALSE; |
||
622 | } |
||
623 | |||
624 | if (osmesa->format == OSMESA_RGB_565 && type != GL_UNSIGNED_SHORT_5_6_5) { |
||
625 | return GL_FALSE; |
||
626 | } |
||
627 | |||
628 | color_format = osmesa_choose_format(osmesa->format, type); |
||
629 | if (color_format == PIPE_FORMAT_NONE) { |
||
630 | fprintf(stderr, "OSMesaMakeCurrent(unsupported format/type)\n"); |
||
631 | return GL_FALSE; |
||
632 | } |
||
633 | |||
634 | /* See if we already have a buffer that uses these pixel formats */ |
||
635 | osbuffer = osmesa_find_buffer(color_format, |
||
636 | osmesa->depth_stencil_format, |
||
637 | osmesa->accum_format); |
||
638 | if (!osbuffer) { |
||
639 | /* Existing buffer found, create new buffer */ |
||
640 | osbuffer = osmesa_create_buffer(color_format, |
||
641 | osmesa->depth_stencil_format, |
||
642 | osmesa->accum_format); |
||
643 | } |
||
644 | |||
645 | osbuffer->width = width; |
||
646 | osbuffer->height = height; |
||
647 | osbuffer->map = buffer; |
||
648 | |||
649 | /* XXX unused for now */ |
||
650 | (void) osmesa_destroy_buffer; |
||
651 | |||
652 | osmesa->current_buffer = osbuffer; |
||
653 | osmesa->type = type; |
||
654 | |||
655 | stapi->make_current(stapi, osmesa->stctx, osbuffer->stfb, osbuffer->stfb); |
||
656 | |||
657 | return GL_TRUE; |
||
658 | } |
||
659 | |||
660 | |||
661 | |||
662 | GLAPI OSMesaContext GLAPIENTRY |
||
663 | OSMesaGetCurrentContext(void) |
||
664 | { |
||
665 | struct st_api *stapi = get_st_api(); |
||
666 | struct st_context_iface *st = stapi->get_current(stapi); |
||
667 | return st ? (OSMesaContext) st->st_manager_private : NULL; |
||
668 | } |
||
669 | |||
670 | |||
671 | |||
672 | GLAPI void GLAPIENTRY |
||
673 | OSMesaPixelStore(GLint pname, GLint value) |
||
674 | { |
||
675 | OSMesaContext osmesa = OSMesaGetCurrentContext(); |
||
676 | |||
677 | switch (pname) { |
||
678 | case OSMESA_ROW_LENGTH: |
||
679 | osmesa->user_row_length = value; |
||
680 | break; |
||
681 | case OSMESA_Y_UP: |
||
682 | osmesa->y_up = value ? GL_TRUE : GL_FALSE; |
||
683 | break; |
||
684 | default: |
||
685 | fprintf(stderr, "Invalid pname in OSMesaPixelStore()\n"); |
||
686 | return; |
||
687 | } |
||
688 | } |
||
689 | |||
690 | |||
691 | GLAPI void GLAPIENTRY |
||
692 | OSMesaGetIntegerv(GLint pname, GLint *value) |
||
693 | { |
||
694 | OSMesaContext osmesa = OSMesaGetCurrentContext(); |
||
695 | struct osmesa_buffer *osbuffer = osmesa ? osmesa->current_buffer : NULL; |
||
696 | |||
697 | switch (pname) { |
||
698 | case OSMESA_WIDTH: |
||
699 | *value = osbuffer ? osbuffer->width : 0; |
||
700 | return; |
||
701 | case OSMESA_HEIGHT: |
||
702 | *value = osbuffer ? osbuffer->height : 0; |
||
703 | return; |
||
704 | case OSMESA_FORMAT: |
||
705 | *value = osmesa->format; |
||
706 | return; |
||
707 | case OSMESA_TYPE: |
||
708 | /* current color buffer's data type */ |
||
709 | *value = osmesa->type; |
||
710 | return; |
||
711 | case OSMESA_ROW_LENGTH: |
||
712 | *value = osmesa->user_row_length; |
||
713 | return; |
||
714 | case OSMESA_Y_UP: |
||
715 | *value = osmesa->y_up; |
||
716 | return; |
||
717 | case OSMESA_MAX_WIDTH: |
||
718 | /* fall-through */ |
||
719 | case OSMESA_MAX_HEIGHT: |
||
720 | { |
||
721 | struct pipe_screen *screen = get_st_manager()->screen; |
||
722 | int maxLevels = screen->get_param(screen, |
||
723 | PIPE_CAP_MAX_TEXTURE_2D_LEVELS); |
||
724 | *value = 1 << (maxLevels - 1); |
||
725 | *value = 8 * 1024; |
||
726 | } |
||
727 | return; |
||
728 | default: |
||
729 | fprintf(stderr, "Invalid pname in OSMesaGetIntegerv()\n"); |
||
730 | return; |
||
731 | } |
||
732 | } |
||
733 | |||
734 | |||
735 | /** |
||
736 | * Return information about the depth buffer associated with an OSMesa context. |
||
737 | * Input: c - the OSMesa context |
||
738 | * Output: width, height - size of buffer in pixels |
||
739 | * bytesPerValue - bytes per depth value (2 or 4) |
||
740 | * buffer - pointer to depth buffer values |
||
741 | * Return: GL_TRUE or GL_FALSE to indicate success or failure. |
||
742 | */ |
||
743 | GLAPI GLboolean GLAPIENTRY |
||
744 | OSMesaGetDepthBuffer(OSMesaContext c, GLint *width, GLint *height, |
||
745 | GLint *bytesPerValue, void **buffer) |
||
746 | { |
||
747 | struct osmesa_buffer *osbuffer = c->current_buffer; |
||
748 | struct pipe_context *pipe = c->stctx->pipe; |
||
749 | struct pipe_resource *res = osbuffer->textures[ST_ATTACHMENT_DEPTH_STENCIL]; |
||
750 | struct pipe_transfer *transfer = NULL; |
||
751 | struct pipe_box box; |
||
752 | |||
753 | /* |
||
754 | * Note: we can't really implement this function with gallium as |
||
755 | * we did for swrast. We can't just map the resource and leave it |
||
756 | * mapped (and there's no OSMesaUnmapDepthBuffer() function) so |
||
757 | * we unmap the buffer here and return a 'stale' pointer. This should |
||
758 | * actually be OK in most cases where the caller of this function |
||
759 | * immediately uses the pointer. |
||
760 | */ |
||
761 | |||
762 | u_box_2d(0, 0, res->width0, res->height0, &box); |
||
763 | |||
764 | *buffer = pipe->transfer_map(pipe, res, 0, PIPE_TRANSFER_READ, &box, |
||
765 | &transfer); |
||
766 | if (!*buffer) { |
||
767 | return GL_FALSE; |
||
768 | } |
||
769 | |||
770 | *width = res->width0; |
||
771 | *height = res->height0; |
||
772 | *bytesPerValue = util_format_get_blocksize(res->format); |
||
773 | |||
774 | pipe->transfer_unmap(pipe, transfer); |
||
775 | |||
776 | return GL_TRUE; |
||
777 | } |
||
778 | |||
779 | |||
780 | /** |
||
781 | * Return the color buffer associated with an OSMesa context. |
||
782 | * Input: c - the OSMesa context |
||
783 | * Output: width, height - size of buffer in pixels |
||
784 | * format - the pixel format (OSMESA_FORMAT) |
||
785 | * buffer - pointer to color buffer values |
||
786 | * Return: GL_TRUE or GL_FALSE to indicate success or failure. |
||
787 | */ |
||
788 | GLAPI GLboolean GLAPIENTRY |
||
789 | OSMesaGetColorBuffer(OSMesaContext osmesa, GLint *width, |
||
790 | GLint *height, GLint *format, void **buffer) |
||
791 | { |
||
792 | struct osmesa_buffer *osbuffer = osmesa->current_buffer; |
||
793 | |||
794 | if (osbuffer) { |
||
795 | *width = osbuffer->width; |
||
796 | *height = osbuffer->height; |
||
797 | *format = osmesa->format; |
||
798 | *buffer = osbuffer->map; |
||
799 | return GL_TRUE; |
||
800 | } |
||
801 | else { |
||
802 | *width = 0; |
||
803 | *height = 0; |
||
804 | *format = 0; |
||
805 | *buffer = 0; |
||
806 | return GL_FALSE; |
||
807 | } |
||
808 | } |
||
809 | |||
810 | |||
811 | struct name_function |
||
812 | { |
||
813 | const char *Name; |
||
814 | OSMESAproc Function; |
||
815 | }; |
||
816 | |||
817 | static struct name_function functions[] = { |
||
818 | { "OSMesaCreateContext", (OSMESAproc) OSMesaCreateContext }, |
||
819 | { "OSMesaCreateContextExt", (OSMESAproc) OSMesaCreateContextExt }, |
||
820 | { "OSMesaDestroyContext", (OSMESAproc) OSMesaDestroyContext }, |
||
821 | { "OSMesaMakeCurrent", (OSMESAproc) OSMesaMakeCurrent }, |
||
822 | { "OSMesaGetCurrentContext", (OSMESAproc) OSMesaGetCurrentContext }, |
||
823 | { "OSMesaPixelsStore", (OSMESAproc) OSMesaPixelStore }, |
||
824 | { "OSMesaGetIntegerv", (OSMESAproc) OSMesaGetIntegerv }, |
||
825 | { "OSMesaGetDepthBuffer", (OSMESAproc) OSMesaGetDepthBuffer }, |
||
826 | { "OSMesaGetColorBuffer", (OSMESAproc) OSMesaGetColorBuffer }, |
||
827 | { "OSMesaGetProcAddress", (OSMESAproc) OSMesaGetProcAddress }, |
||
828 | { "OSMesaColorClamp", (OSMESAproc) OSMesaColorClamp }, |
||
829 | { NULL, NULL } |
||
830 | }; |
||
831 | |||
832 | |||
833 | GLAPI OSMESAproc GLAPIENTRY |
||
834 | OSMesaGetProcAddress(const char *funcName) |
||
835 | { |
||
836 | int i; |
||
837 | for (i = 0; functions[i].Name; i++) { |
||
838 | if (strcmp(functions[i].Name, funcName) == 0) |
||
839 | return functions[i].Function; |
||
840 | } |
||
841 | return _glapi_get_proc_address(funcName); |
||
842 | } |
||
843 | |||
844 | |||
845 | GLAPI void GLAPIENTRY |
||
846 | OSMesaColorClamp(GLboolean enable) |
||
847 | { |
||
848 | extern void GLAPIENTRY _mesa_ClampColor(GLenum target, GLenum clamp); |
||
849 | |||
850 | _mesa_ClampColor(GL_CLAMP_FRAGMENT_COLOR_ARB, |
||
851 | enable ? GL_TRUE : GL_FIXED_ONLY_ARB); |
||
852 | }><>>>>>>>>>>> |