Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/gallium/frontends/osmesa/osmesa.c
4565 views
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
* OpenGL gallium frontend 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 support "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 <stdio.h>
53
#include <c11/threads.h>
54
#include "GL/osmesa.h"
55
56
#include "glapi/glapi.h" /* for OSMesaGetProcAddress below */
57
58
#include "pipe/p_context.h"
59
#include "pipe/p_screen.h"
60
#include "pipe/p_state.h"
61
62
#include "util/u_atomic.h"
63
#include "util/u_box.h"
64
#include "util/u_debug.h"
65
#include "util/format/u_format.h"
66
#include "util/u_inlines.h"
67
#include "util/u_memory.h"
68
69
#include "postprocess/filters.h"
70
#include "postprocess/postprocess.h"
71
72
#include "frontend/api.h"
73
#include "state_tracker/st_gl_api.h"
74
75
76
77
extern struct pipe_screen *
78
osmesa_create_screen(void);
79
80
81
82
struct osmesa_buffer
83
{
84
struct st_framebuffer_iface *stfb;
85
struct st_visual visual;
86
unsigned width, height;
87
88
struct pipe_resource *textures[ST_ATTACHMENT_COUNT];
89
90
void *map;
91
92
struct osmesa_buffer *next; /**< next in linked list */
93
};
94
95
96
struct osmesa_context
97
{
98
struct st_context_iface *stctx;
99
100
boolean ever_used; /*< Has this context ever been current? */
101
102
struct osmesa_buffer *current_buffer;
103
104
/* Storage for depth/stencil, if the user has requested access. The backing
105
* driver always has its own storage for the actual depth/stencil, which we
106
* have to transfer in and out.
107
*/
108
void *zs;
109
unsigned zs_stride;
110
111
enum pipe_format depth_stencil_format, accum_format;
112
113
GLenum format; /*< User-specified context format */
114
GLenum type; /*< Buffer's data type */
115
GLint user_row_length; /*< user-specified number of pixels per row */
116
GLboolean y_up; /*< TRUE -> Y increases upward */
117
/*< FALSE -> Y increases downward */
118
119
/** Which postprocessing filters are enabled. */
120
unsigned pp_enabled[PP_FILTERS];
121
struct pp_queue_t *pp;
122
};
123
124
/**
125
* Called from the ST manager.
126
*/
127
static int
128
osmesa_st_get_param(struct st_manager *smapi, enum st_manager_param param)
129
{
130
/* no-op */
131
return 0;
132
}
133
134
static struct st_manager *stmgr = NULL;
135
static struct st_api *stapi = NULL;
136
137
static void
138
destroy_st_manager(void)
139
{
140
if (stmgr) {
141
if (stmgr->screen)
142
stmgr->screen->destroy(stmgr->screen);
143
FREE(stmgr);
144
}
145
146
if (stapi && stapi->destroy) {
147
stapi->destroy(stapi);
148
}
149
}
150
151
static void
152
create_st_manager(void)
153
{
154
if (atexit(destroy_st_manager) != 0)
155
return;
156
157
stmgr = CALLOC_STRUCT(st_manager);
158
if (stmgr) {
159
stmgr->screen = osmesa_create_screen();
160
stmgr->get_param = osmesa_st_get_param;
161
stmgr->get_egl_image = NULL;
162
}
163
164
stapi = st_gl_api_create();
165
debug_printf("OSMESA: stmgr=%p; stapi=%p\n",stmgr,stapi);
166
}
167
168
/**
169
* Create/return a singleton st_manager object.
170
*/
171
static struct st_manager *
172
get_st_manager(void)
173
{
174
static once_flag create_once_flag = ONCE_FLAG_INIT;
175
176
call_once(&create_once_flag, create_st_manager);
177
178
return stmgr;
179
}
180
181
/**
182
* Create/return singleton st_api object.
183
*/
184
static struct st_api *
185
get_st_api(void)
186
{
187
get_st_manager();
188
return stapi;
189
}
190
191
/* Reads the color or depth buffer from the backing context to either the user storage
192
* (color buffer) or our temporary (z/s)
193
*/
194
static void
195
osmesa_read_buffer(OSMesaContext osmesa, struct pipe_resource *res, void *dst,
196
int dst_stride, bool y_up)
197
{
198
struct pipe_context *pipe = osmesa->stctx->pipe;
199
200
struct pipe_box box;
201
u_box_2d(0, 0, res->width0, res->height0, &box);
202
203
struct pipe_transfer *transfer = NULL;
204
ubyte *src = pipe->texture_map(pipe, res, 0, PIPE_MAP_READ, &box,
205
&transfer);
206
207
/*
208
* Copy the color buffer from the resource to the user's buffer.
209
*/
210
211
if (y_up) {
212
/* need to flip image upside down */
213
dst = (ubyte *)dst + (res->height0 - 1) * dst_stride;
214
dst_stride = -dst_stride;
215
}
216
217
unsigned bpp = util_format_get_blocksize(res->format);
218
for (unsigned y = 0; y < res->height0; y++)
219
{
220
memcpy(dst, src, bpp * res->width0);
221
dst = (ubyte *)dst + dst_stride;
222
src += transfer->stride;
223
}
224
225
pipe->texture_unmap(pipe, transfer);
226
}
227
228
229
/**
230
* Given an OSMESA_x format and a GL_y type, return the best
231
* matching PIPE_FORMAT_z.
232
* Note that we can't exactly match all user format/type combinations
233
* with gallium formats. If we find this to be a problem, we can
234
* implement more elaborate format/type conversion in the flush_front()
235
* function.
236
*/
237
static enum pipe_format
238
osmesa_choose_format(GLenum format, GLenum type)
239
{
240
switch (format) {
241
case OSMESA_RGBA:
242
if (type == GL_UNSIGNED_BYTE) {
243
#if UTIL_ARCH_LITTLE_ENDIAN
244
return PIPE_FORMAT_R8G8B8A8_UNORM;
245
#else
246
return PIPE_FORMAT_A8B8G8R8_UNORM;
247
#endif
248
}
249
else if (type == GL_UNSIGNED_SHORT) {
250
return PIPE_FORMAT_R16G16B16A16_UNORM;
251
}
252
else if (type == GL_FLOAT) {
253
return PIPE_FORMAT_R32G32B32A32_FLOAT;
254
}
255
else {
256
return PIPE_FORMAT_NONE;
257
}
258
break;
259
case OSMESA_BGRA:
260
if (type == GL_UNSIGNED_BYTE) {
261
#if UTIL_ARCH_LITTLE_ENDIAN
262
return PIPE_FORMAT_B8G8R8A8_UNORM;
263
#else
264
return PIPE_FORMAT_A8R8G8B8_UNORM;
265
#endif
266
}
267
else if (type == GL_UNSIGNED_SHORT) {
268
return PIPE_FORMAT_R16G16B16A16_UNORM;
269
}
270
else if (type == GL_FLOAT) {
271
return PIPE_FORMAT_R32G32B32A32_FLOAT;
272
}
273
else {
274
return PIPE_FORMAT_NONE;
275
}
276
break;
277
case OSMESA_ARGB:
278
if (type == GL_UNSIGNED_BYTE) {
279
#if UTIL_ARCH_LITTLE_ENDIAN
280
return PIPE_FORMAT_A8R8G8B8_UNORM;
281
#else
282
return PIPE_FORMAT_B8G8R8A8_UNORM;
283
#endif
284
}
285
else if (type == GL_UNSIGNED_SHORT) {
286
return PIPE_FORMAT_R16G16B16A16_UNORM;
287
}
288
else if (type == GL_FLOAT) {
289
return PIPE_FORMAT_R32G32B32A32_FLOAT;
290
}
291
else {
292
return PIPE_FORMAT_NONE;
293
}
294
break;
295
case OSMESA_RGB:
296
if (type == GL_UNSIGNED_BYTE) {
297
return PIPE_FORMAT_R8G8B8_UNORM;
298
}
299
else if (type == GL_UNSIGNED_SHORT) {
300
return PIPE_FORMAT_R16G16B16_UNORM;
301
}
302
else if (type == GL_FLOAT) {
303
return PIPE_FORMAT_R32G32B32_FLOAT;
304
}
305
else {
306
return PIPE_FORMAT_NONE;
307
}
308
break;
309
case OSMESA_BGR:
310
/* No gallium format for this one */
311
return PIPE_FORMAT_NONE;
312
case OSMESA_RGB_565:
313
if (type != GL_UNSIGNED_SHORT_5_6_5)
314
return PIPE_FORMAT_NONE;
315
return PIPE_FORMAT_B5G6R5_UNORM;
316
default:
317
return PIPE_FORMAT_NONE;
318
}
319
}
320
321
322
/**
323
* Initialize an st_visual object.
324
*/
325
static void
326
osmesa_init_st_visual(struct st_visual *vis,
327
enum pipe_format color_format,
328
enum pipe_format ds_format,
329
enum pipe_format accum_format)
330
{
331
vis->buffer_mask = ST_ATTACHMENT_FRONT_LEFT_MASK;
332
333
if (ds_format != PIPE_FORMAT_NONE)
334
vis->buffer_mask |= ST_ATTACHMENT_DEPTH_STENCIL_MASK;
335
if (accum_format != PIPE_FORMAT_NONE)
336
vis->buffer_mask |= ST_ATTACHMENT_ACCUM;
337
338
vis->color_format = color_format;
339
vis->depth_stencil_format = ds_format;
340
vis->accum_format = accum_format;
341
vis->samples = 1;
342
}
343
344
345
/**
346
* Return the osmesa_buffer that corresponds to an st_framebuffer_iface.
347
*/
348
static inline struct osmesa_buffer *
349
stfbi_to_osbuffer(struct st_framebuffer_iface *stfbi)
350
{
351
return (struct osmesa_buffer *) stfbi->st_manager_private;
352
}
353
354
355
/**
356
* Called via glFlush/glFinish. This is where we copy the contents
357
* of the driver's color buffer into the user-specified buffer.
358
*/
359
static bool
360
osmesa_st_framebuffer_flush_front(struct st_context_iface *stctx,
361
struct st_framebuffer_iface *stfbi,
362
enum st_attachment_type statt)
363
{
364
OSMesaContext osmesa = OSMesaGetCurrentContext();
365
struct osmesa_buffer *osbuffer = stfbi_to_osbuffer(stfbi);
366
struct pipe_resource *res = osbuffer->textures[statt];
367
unsigned bpp;
368
int dst_stride;
369
370
if (statt != ST_ATTACHMENT_FRONT_LEFT)
371
return false;
372
373
if (osmesa->pp) {
374
struct pipe_resource *zsbuf = NULL;
375
unsigned i;
376
377
/* Find the z/stencil buffer if there is one */
378
for (i = 0; i < ARRAY_SIZE(osbuffer->textures); i++) {
379
struct pipe_resource *res = osbuffer->textures[i];
380
if (res) {
381
const struct util_format_description *desc =
382
util_format_description(res->format);
383
384
if (util_format_has_depth(desc)) {
385
zsbuf = res;
386
break;
387
}
388
}
389
}
390
391
/* run the postprocess stage(s) */
392
pp_run(osmesa->pp, res, res, zsbuf);
393
}
394
395
/* Snapshot the color buffer to the user's buffer. */
396
bpp = util_format_get_blocksize(osbuffer->visual.color_format);
397
if (osmesa->user_row_length)
398
dst_stride = bpp * osmesa->user_row_length;
399
else
400
dst_stride = bpp * osbuffer->width;
401
402
osmesa_read_buffer(osmesa, res, osbuffer->map, dst_stride, osmesa->y_up);
403
404
/* If the user has requested the Z/S buffer, then snapshot that one too. */
405
if (osmesa->zs) {
406
osmesa_read_buffer(osmesa, osbuffer->textures[ST_ATTACHMENT_DEPTH_STENCIL],
407
osmesa->zs, osmesa->zs_stride, true);
408
}
409
410
return true;
411
}
412
413
414
/**
415
* Called by the st manager to validate the framebuffer (allocate
416
* its resources).
417
*/
418
static bool
419
osmesa_st_framebuffer_validate(struct st_context_iface *stctx,
420
struct st_framebuffer_iface *stfbi,
421
const enum st_attachment_type *statts,
422
unsigned count,
423
struct pipe_resource **out)
424
{
425
struct pipe_screen *screen = get_st_manager()->screen;
426
enum st_attachment_type i;
427
struct osmesa_buffer *osbuffer = stfbi_to_osbuffer(stfbi);
428
struct pipe_resource templat;
429
430
memset(&templat, 0, sizeof(templat));
431
templat.target = PIPE_TEXTURE_RECT;
432
templat.format = 0; /* setup below */
433
templat.last_level = 0;
434
templat.width0 = osbuffer->width;
435
templat.height0 = osbuffer->height;
436
templat.depth0 = 1;
437
templat.array_size = 1;
438
templat.usage = PIPE_USAGE_DEFAULT;
439
templat.bind = 0; /* setup below */
440
templat.flags = 0;
441
442
for (i = 0; i < count; i++) {
443
enum pipe_format format = PIPE_FORMAT_NONE;
444
unsigned bind = 0;
445
446
/*
447
* At this time, we really only need to handle the front-left color
448
* attachment, since that's all we specified for the visual in
449
* osmesa_init_st_visual().
450
*/
451
if (statts[i] == ST_ATTACHMENT_FRONT_LEFT) {
452
format = osbuffer->visual.color_format;
453
bind = PIPE_BIND_RENDER_TARGET;
454
}
455
else if (statts[i] == ST_ATTACHMENT_DEPTH_STENCIL) {
456
format = osbuffer->visual.depth_stencil_format;
457
bind = PIPE_BIND_DEPTH_STENCIL;
458
}
459
else if (statts[i] == ST_ATTACHMENT_ACCUM) {
460
format = osbuffer->visual.accum_format;
461
bind = PIPE_BIND_RENDER_TARGET;
462
}
463
else {
464
debug_warning("Unexpected attachment type in "
465
"osmesa_st_framebuffer_validate()");
466
}
467
468
templat.format = format;
469
templat.bind = bind;
470
pipe_resource_reference(&out[i], NULL);
471
out[i] = osbuffer->textures[statts[i]] =
472
screen->resource_create(screen, &templat);
473
}
474
475
return true;
476
}
477
478
static uint32_t osmesa_fb_ID = 0;
479
480
static struct st_framebuffer_iface *
481
osmesa_create_st_framebuffer(void)
482
{
483
struct st_framebuffer_iface *stfbi = CALLOC_STRUCT(st_framebuffer_iface);
484
if (stfbi) {
485
stfbi->flush_front = osmesa_st_framebuffer_flush_front;
486
stfbi->validate = osmesa_st_framebuffer_validate;
487
p_atomic_set(&stfbi->stamp, 1);
488
stfbi->ID = p_atomic_inc_return(&osmesa_fb_ID);
489
stfbi->state_manager = get_st_manager();
490
}
491
return stfbi;
492
}
493
494
495
/**
496
* Create new buffer and add to linked list.
497
*/
498
static struct osmesa_buffer *
499
osmesa_create_buffer(enum pipe_format color_format,
500
enum pipe_format ds_format,
501
enum pipe_format accum_format)
502
{
503
struct osmesa_buffer *osbuffer = CALLOC_STRUCT(osmesa_buffer);
504
if (osbuffer) {
505
osbuffer->stfb = osmesa_create_st_framebuffer();
506
507
osbuffer->stfb->st_manager_private = osbuffer;
508
osbuffer->stfb->visual = &osbuffer->visual;
509
510
osmesa_init_st_visual(&osbuffer->visual, color_format,
511
ds_format, accum_format);
512
}
513
514
return osbuffer;
515
}
516
517
518
static void
519
osmesa_destroy_buffer(struct osmesa_buffer *osbuffer)
520
{
521
/*
522
* Notify the state manager that the associated framebuffer interface
523
* is no longer valid.
524
*/
525
stapi->destroy_drawable(stapi, osbuffer->stfb);
526
527
FREE(osbuffer->stfb);
528
FREE(osbuffer);
529
}
530
531
532
533
/**********************************************************************/
534
/***** Public Functions *****/
535
/**********************************************************************/
536
537
538
/**
539
* Create an Off-Screen Mesa rendering context. The only attribute needed is
540
* an RGBA vs Color-Index mode flag.
541
*
542
* Input: format - Must be GL_RGBA
543
* sharelist - specifies another OSMesaContext with which to share
544
* display lists. NULL indicates no sharing.
545
* Return: an OSMesaContext or 0 if error
546
*/
547
GLAPI OSMesaContext GLAPIENTRY
548
OSMesaCreateContext(GLenum format, OSMesaContext sharelist)
549
{
550
return OSMesaCreateContextExt(format, 24, 8, 0, sharelist);
551
}
552
553
554
/**
555
* New in Mesa 3.5
556
*
557
* Create context and specify size of ancillary buffers.
558
*/
559
GLAPI OSMesaContext GLAPIENTRY
560
OSMesaCreateContextExt(GLenum format, GLint depthBits, GLint stencilBits,
561
GLint accumBits, OSMesaContext sharelist)
562
{
563
int attribs[100], n = 0;
564
565
attribs[n++] = OSMESA_FORMAT;
566
attribs[n++] = format;
567
attribs[n++] = OSMESA_DEPTH_BITS;
568
attribs[n++] = depthBits;
569
attribs[n++] = OSMESA_STENCIL_BITS;
570
attribs[n++] = stencilBits;
571
attribs[n++] = OSMESA_ACCUM_BITS;
572
attribs[n++] = accumBits;
573
attribs[n++] = 0;
574
575
return OSMesaCreateContextAttribs(attribs, sharelist);
576
}
577
578
579
/**
580
* New in Mesa 11.2
581
*
582
* Create context with attribute list.
583
*/
584
GLAPI OSMesaContext GLAPIENTRY
585
OSMesaCreateContextAttribs(const int *attribList, OSMesaContext sharelist)
586
{
587
OSMesaContext osmesa;
588
struct st_context_iface *st_shared;
589
enum st_context_error st_error = 0;
590
struct st_context_attribs attribs;
591
struct st_api *stapi = get_st_api();
592
GLenum format = GL_RGBA;
593
int depthBits = 0, stencilBits = 0, accumBits = 0;
594
int profile = OSMESA_COMPAT_PROFILE, version_major = 1, version_minor = 0;
595
int i;
596
597
if (sharelist) {
598
st_shared = sharelist->stctx;
599
}
600
else {
601
st_shared = NULL;
602
}
603
604
for (i = 0; attribList[i]; i += 2) {
605
switch (attribList[i]) {
606
case OSMESA_FORMAT:
607
format = attribList[i+1];
608
switch (format) {
609
case OSMESA_COLOR_INDEX:
610
case OSMESA_RGBA:
611
case OSMESA_BGRA:
612
case OSMESA_ARGB:
613
case OSMESA_RGB:
614
case OSMESA_BGR:
615
case OSMESA_RGB_565:
616
/* legal */
617
break;
618
default:
619
return NULL;
620
}
621
break;
622
case OSMESA_DEPTH_BITS:
623
depthBits = attribList[i+1];
624
if (depthBits < 0)
625
return NULL;
626
break;
627
case OSMESA_STENCIL_BITS:
628
stencilBits = attribList[i+1];
629
if (stencilBits < 0)
630
return NULL;
631
break;
632
case OSMESA_ACCUM_BITS:
633
accumBits = attribList[i+1];
634
if (accumBits < 0)
635
return NULL;
636
break;
637
case OSMESA_PROFILE:
638
profile = attribList[i+1];
639
if (profile != OSMESA_CORE_PROFILE &&
640
profile != OSMESA_COMPAT_PROFILE)
641
return NULL;
642
break;
643
case OSMESA_CONTEXT_MAJOR_VERSION:
644
version_major = attribList[i+1];
645
if (version_major < 1)
646
return NULL;
647
break;
648
case OSMESA_CONTEXT_MINOR_VERSION:
649
version_minor = attribList[i+1];
650
if (version_minor < 0)
651
return NULL;
652
break;
653
case 0:
654
/* end of list */
655
break;
656
default:
657
fprintf(stderr, "Bad attribute in OSMesaCreateContextAttribs()\n");
658
return NULL;
659
}
660
}
661
662
osmesa = (OSMesaContext) CALLOC_STRUCT(osmesa_context);
663
if (!osmesa)
664
return NULL;
665
666
/* Choose depth/stencil/accum buffer formats */
667
if (accumBits > 0) {
668
osmesa->accum_format = PIPE_FORMAT_R16G16B16A16_SNORM;
669
}
670
if (depthBits > 0 && stencilBits > 0) {
671
osmesa->depth_stencil_format = PIPE_FORMAT_Z24_UNORM_S8_UINT;
672
}
673
else if (stencilBits > 0) {
674
osmesa->depth_stencil_format = PIPE_FORMAT_S8_UINT;
675
}
676
else if (depthBits >= 24) {
677
osmesa->depth_stencil_format = PIPE_FORMAT_Z24X8_UNORM;
678
}
679
else if (depthBits >= 16) {
680
osmesa->depth_stencil_format = PIPE_FORMAT_Z16_UNORM;
681
}
682
683
/*
684
* Create the rendering context
685
*/
686
memset(&attribs, 0, sizeof(attribs));
687
attribs.profile = (profile == OSMESA_CORE_PROFILE)
688
? ST_PROFILE_OPENGL_CORE : ST_PROFILE_DEFAULT;
689
attribs.major = version_major;
690
attribs.minor = version_minor;
691
attribs.flags = 0; /* ST_CONTEXT_FLAG_x */
692
attribs.options.force_glsl_extensions_warn = FALSE;
693
attribs.options.disable_blend_func_extended = FALSE;
694
attribs.options.disable_glsl_line_continuations = FALSE;
695
attribs.options.force_glsl_version = 0;
696
697
osmesa_init_st_visual(&attribs.visual,
698
PIPE_FORMAT_NONE,
699
osmesa->depth_stencil_format,
700
osmesa->accum_format);
701
702
osmesa->stctx = stapi->create_context(stapi, get_st_manager(),
703
&attribs, &st_error, st_shared);
704
if (!osmesa->stctx) {
705
char* st_error_str;
706
switch (st_error) {
707
case ST_CONTEXT_ERROR_NO_MEMORY:
708
st_error_str="ST_CONTEXT_ERROR_NO_MEMORY";
709
break;
710
case ST_CONTEXT_ERROR_BAD_API:
711
st_error_str="ST_CONTEXT_ERROR_BAD_API";
712
break;
713
case ST_CONTEXT_ERROR_BAD_VERSION:
714
st_error_str="ST_CONTEXT_ERROR_BAD_VERSION";
715
break;
716
case ST_CONTEXT_ERROR_BAD_FLAG:
717
st_error_str="ST_CONTEXT_ERROR_BAD_FLAG";
718
break;
719
case ST_CONTEXT_ERROR_UNKNOWN_ATTRIBUTE:
720
st_error_str="ST_CONTEXT_ERROR_UNKNOWN_ATTRIBUTE";
721
break;
722
case ST_CONTEXT_ERROR_UNKNOWN_FLAG:
723
st_error_str="ST_CONTEXT_ERROR_UNKNOWN_FLAG";
724
break;
725
default:
726
st_error_str="UNKNOWN";
727
break;
728
}
729
debug_printf("OSMESA: error: unable to create st context, st_error=%s",st_error_str);
730
FREE(osmesa);
731
return NULL;
732
}
733
734
osmesa->stctx->st_manager_private = osmesa;
735
736
osmesa->format = format;
737
osmesa->user_row_length = 0;
738
osmesa->y_up = GL_TRUE;
739
740
return osmesa;
741
}
742
743
744
745
/**
746
* Destroy an Off-Screen Mesa rendering context.
747
*
748
* \param osmesa the context to destroy
749
*/
750
GLAPI void GLAPIENTRY
751
OSMesaDestroyContext(OSMesaContext osmesa)
752
{
753
if (osmesa) {
754
pp_free(osmesa->pp);
755
osmesa->stctx->destroy(osmesa->stctx);
756
free(osmesa->zs);
757
FREE(osmesa);
758
}
759
}
760
761
762
/**
763
* Bind an OSMesaContext to an image buffer. The image buffer is just a
764
* block of memory which the client provides. Its size must be at least
765
* as large as width*height*pixelSize. Its address should be a multiple
766
* of 4 if using RGBA mode.
767
*
768
* By default, image data is stored in the order of glDrawPixels: row-major
769
* order with the lower-left image pixel stored in the first array position
770
* (ie. bottom-to-top).
771
*
772
* If the context's viewport hasn't been initialized yet, it will now be
773
* initialized to (0,0,width,height).
774
*
775
* Input: osmesa - the rendering context
776
* buffer - the image buffer memory
777
* type - data type for pixel components
778
* GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_SHORT
779
* or GL_FLOAT.
780
* width, height - size of image buffer in pixels, at least 1
781
* Return: GL_TRUE if success, GL_FALSE if error because of invalid osmesa,
782
* invalid type, invalid size, etc.
783
*/
784
GLAPI GLboolean GLAPIENTRY
785
OSMesaMakeCurrent(OSMesaContext osmesa, void *buffer, GLenum type,
786
GLsizei width, GLsizei height)
787
{
788
struct st_api *stapi = get_st_api();
789
enum pipe_format color_format;
790
791
if (!osmesa && !buffer) {
792
stapi->make_current(stapi, NULL, NULL, NULL);
793
return GL_TRUE;
794
}
795
796
if (!osmesa || !buffer || width < 1 || height < 1) {
797
return GL_FALSE;
798
}
799
800
color_format = osmesa_choose_format(osmesa->format, type);
801
if (color_format == PIPE_FORMAT_NONE) {
802
fprintf(stderr, "OSMesaMakeCurrent(unsupported format/type)\n");
803
return GL_FALSE;
804
}
805
806
/* See if we already have a buffer that uses these pixel formats */
807
if (osmesa->current_buffer &&
808
(osmesa->current_buffer->visual.color_format != color_format ||
809
osmesa->current_buffer->visual.depth_stencil_format != osmesa->depth_stencil_format ||
810
osmesa->current_buffer->visual.accum_format != osmesa->accum_format)) {
811
osmesa_destroy_buffer(osmesa->current_buffer);
812
}
813
814
if (!osmesa->current_buffer) {
815
osmesa->current_buffer = osmesa_create_buffer(color_format,
816
osmesa->depth_stencil_format,
817
osmesa->accum_format);
818
}
819
820
struct osmesa_buffer *osbuffer = osmesa->current_buffer;
821
822
osbuffer->width = width;
823
osbuffer->height = height;
824
osbuffer->map = buffer;
825
826
osmesa->type = type;
827
828
stapi->make_current(stapi, osmesa->stctx, osbuffer->stfb, osbuffer->stfb);
829
830
/* XXX: We should probably load the current color value into the buffer here
831
* to match classic swrast behavior (context's fb starts with the contents of
832
* your pixel buffer).
833
*/
834
835
if (!osmesa->ever_used) {
836
/* one-time init, just postprocessing for now */
837
boolean any_pp_enabled = FALSE;
838
unsigned i;
839
840
for (i = 0; i < ARRAY_SIZE(osmesa->pp_enabled); i++) {
841
if (osmesa->pp_enabled[i]) {
842
any_pp_enabled = TRUE;
843
break;
844
}
845
}
846
847
if (any_pp_enabled) {
848
osmesa->pp = pp_init(osmesa->stctx->pipe,
849
osmesa->pp_enabled,
850
osmesa->stctx->cso_context,
851
osmesa->stctx);
852
853
pp_init_fbos(osmesa->pp, width, height);
854
}
855
856
osmesa->ever_used = TRUE;
857
}
858
859
return GL_TRUE;
860
}
861
862
863
864
GLAPI OSMesaContext GLAPIENTRY
865
OSMesaGetCurrentContext(void)
866
{
867
struct st_api *stapi = get_st_api();
868
struct st_context_iface *st = stapi->get_current(stapi);
869
return st ? (OSMesaContext) st->st_manager_private : NULL;
870
}
871
872
873
874
GLAPI void GLAPIENTRY
875
OSMesaPixelStore(GLint pname, GLint value)
876
{
877
OSMesaContext osmesa = OSMesaGetCurrentContext();
878
879
switch (pname) {
880
case OSMESA_ROW_LENGTH:
881
osmesa->user_row_length = value;
882
break;
883
case OSMESA_Y_UP:
884
osmesa->y_up = value ? GL_TRUE : GL_FALSE;
885
break;
886
default:
887
fprintf(stderr, "Invalid pname in OSMesaPixelStore()\n");
888
return;
889
}
890
}
891
892
893
GLAPI void GLAPIENTRY
894
OSMesaGetIntegerv(GLint pname, GLint *value)
895
{
896
OSMesaContext osmesa = OSMesaGetCurrentContext();
897
struct osmesa_buffer *osbuffer = osmesa ? osmesa->current_buffer : NULL;
898
899
switch (pname) {
900
case OSMESA_WIDTH:
901
*value = osbuffer ? osbuffer->width : 0;
902
return;
903
case OSMESA_HEIGHT:
904
*value = osbuffer ? osbuffer->height : 0;
905
return;
906
case OSMESA_FORMAT:
907
*value = osmesa->format;
908
return;
909
case OSMESA_TYPE:
910
/* current color buffer's data type */
911
*value = osmesa->type;
912
return;
913
case OSMESA_ROW_LENGTH:
914
*value = osmesa->user_row_length;
915
return;
916
case OSMESA_Y_UP:
917
*value = osmesa->y_up;
918
return;
919
case OSMESA_MAX_WIDTH:
920
FALLTHROUGH;
921
case OSMESA_MAX_HEIGHT:
922
{
923
struct pipe_screen *screen = get_st_manager()->screen;
924
*value = screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_2D_SIZE);
925
}
926
return;
927
default:
928
fprintf(stderr, "Invalid pname in OSMesaGetIntegerv()\n");
929
return;
930
}
931
}
932
933
934
/**
935
* Return information about the depth buffer associated with an OSMesa context.
936
* Input: c - the OSMesa context
937
* Output: width, height - size of buffer in pixels
938
* bytesPerValue - bytes per depth value (2 or 4)
939
* buffer - pointer to depth buffer values
940
* Return: GL_TRUE or GL_FALSE to indicate success or failure.
941
*/
942
GLAPI GLboolean GLAPIENTRY
943
OSMesaGetDepthBuffer(OSMesaContext c, GLint *width, GLint *height,
944
GLint *bytesPerValue, void **buffer)
945
{
946
struct osmesa_buffer *osbuffer = c->current_buffer;
947
struct pipe_resource *res = osbuffer->textures[ST_ATTACHMENT_DEPTH_STENCIL];
948
949
if (!res) {
950
*width = 0;
951
*height = 0;
952
*bytesPerValue = 0;
953
*buffer = NULL;
954
return GL_FALSE;
955
}
956
957
*width = res->width0;
958
*height = res->height0;
959
*bytesPerValue = util_format_get_blocksize(res->format);
960
961
if (!c->zs) {
962
c->zs_stride = *width * *bytesPerValue;
963
c->zs = calloc(c->zs_stride, *height);
964
if (!c->zs)
965
return GL_FALSE;
966
967
osmesa_read_buffer(c, res, c->zs, c->zs_stride, true);
968
}
969
970
*buffer = c->zs;
971
972
return GL_TRUE;
973
}
974
975
976
/**
977
* Return the color buffer associated with an OSMesa context.
978
* Input: c - the OSMesa context
979
* Output: width, height - size of buffer in pixels
980
* format - the pixel format (OSMESA_FORMAT)
981
* buffer - pointer to color buffer values
982
* Return: GL_TRUE or GL_FALSE to indicate success or failure.
983
*/
984
GLAPI GLboolean GLAPIENTRY
985
OSMesaGetColorBuffer(OSMesaContext osmesa, GLint *width,
986
GLint *height, GLint *format, void **buffer)
987
{
988
struct osmesa_buffer *osbuffer = osmesa->current_buffer;
989
990
if (osbuffer) {
991
*width = osbuffer->width;
992
*height = osbuffer->height;
993
*format = osmesa->format;
994
*buffer = osbuffer->map;
995
return GL_TRUE;
996
}
997
else {
998
*width = 0;
999
*height = 0;
1000
*format = 0;
1001
*buffer = 0;
1002
return GL_FALSE;
1003
}
1004
}
1005
1006
1007
struct name_function
1008
{
1009
const char *Name;
1010
OSMESAproc Function;
1011
};
1012
1013
static struct name_function functions[] = {
1014
{ "OSMesaCreateContext", (OSMESAproc) OSMesaCreateContext },
1015
{ "OSMesaCreateContextExt", (OSMESAproc) OSMesaCreateContextExt },
1016
{ "OSMesaCreateContextAttribs", (OSMESAproc) OSMesaCreateContextAttribs },
1017
{ "OSMesaDestroyContext", (OSMESAproc) OSMesaDestroyContext },
1018
{ "OSMesaMakeCurrent", (OSMESAproc) OSMesaMakeCurrent },
1019
{ "OSMesaGetCurrentContext", (OSMESAproc) OSMesaGetCurrentContext },
1020
{ "OSMesaPixelStore", (OSMESAproc) OSMesaPixelStore },
1021
{ "OSMesaGetIntegerv", (OSMESAproc) OSMesaGetIntegerv },
1022
{ "OSMesaGetDepthBuffer", (OSMESAproc) OSMesaGetDepthBuffer },
1023
{ "OSMesaGetColorBuffer", (OSMESAproc) OSMesaGetColorBuffer },
1024
{ "OSMesaGetProcAddress", (OSMESAproc) OSMesaGetProcAddress },
1025
{ "OSMesaColorClamp", (OSMESAproc) OSMesaColorClamp },
1026
{ "OSMesaPostprocess", (OSMESAproc) OSMesaPostprocess },
1027
{ NULL, NULL }
1028
};
1029
1030
1031
GLAPI OSMESAproc GLAPIENTRY
1032
OSMesaGetProcAddress(const char *funcName)
1033
{
1034
int i;
1035
for (i = 0; functions[i].Name; i++) {
1036
if (strcmp(functions[i].Name, funcName) == 0)
1037
return functions[i].Function;
1038
}
1039
return _glapi_get_proc_address(funcName);
1040
}
1041
1042
1043
GLAPI void GLAPIENTRY
1044
OSMesaColorClamp(GLboolean enable)
1045
{
1046
extern void GLAPIENTRY _mesa_ClampColor(GLenum target, GLenum clamp);
1047
1048
_mesa_ClampColor(GL_CLAMP_FRAGMENT_COLOR_ARB,
1049
enable ? GL_TRUE : GL_FIXED_ONLY_ARB);
1050
}
1051
1052
1053
GLAPI void GLAPIENTRY
1054
OSMesaPostprocess(OSMesaContext osmesa, const char *filter,
1055
unsigned enable_value)
1056
{
1057
if (!osmesa->ever_used) {
1058
/* We can only enable/disable postprocess filters before a context
1059
* is made current for the first time.
1060
*/
1061
unsigned i;
1062
1063
for (i = 0; i < PP_FILTERS; i++) {
1064
if (strcmp(pp_filters[i].name, filter) == 0) {
1065
osmesa->pp_enabled[i] = enable_value;
1066
return;
1067
}
1068
}
1069
debug_warning("OSMesaPostprocess(unknown filter)\n");
1070
}
1071
else {
1072
debug_warning("Calling OSMesaPostprocess() after OSMesaMakeCurrent()\n");
1073
}
1074
}
1075
1076