~mmach/netext73/mesa-haswell

« back to all changes in this revision

Viewing changes to src/gallium/frontends/osmesa/osmesa.c

  • Committer: mmach
  • Date: 2022-09-22 19:56:13 UTC
  • Revision ID: netbit73@gmail.com-20220922195613-wtik9mmy20tmor0i
2022-09-22 21:17:09

Show diffs side-by-side

added added

removed removed

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