1848b8605Smrg/*
2848b8605Smrg * Copyright (c) 2013  Brian Paul   All Rights Reserved.
3848b8605Smrg *
4848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5848b8605Smrg * copy of this software and associated documentation files (the "Software"),
6848b8605Smrg * to deal in the Software without restriction, including without limitation
7848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the
9848b8605Smrg * Software is furnished to do so, subject to the following conditions:
10848b8605Smrg *
11848b8605Smrg * The above copyright notice and this permission notice shall be included
12848b8605Smrg * in all copies or substantial portions of the Software.
13848b8605Smrg *
14848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE.
21848b8605Smrg */
22848b8605Smrg
23848b8605Smrg
24848b8605Smrg/*
25848b8605Smrg * Off-Screen rendering into client memory.
26848b8605Smrg * State tracker for gallium (for softpipe and llvmpipe)
27848b8605Smrg *
28848b8605Smrg * Notes:
29848b8605Smrg *
30848b8605Smrg * If Gallium is built with LLVM support we use the llvmpipe driver.
31848b8605Smrg * Otherwise we use softpipe.  The GALLIUM_DRIVER environment variable
32848b8605Smrg * may be set to "softpipe" or "llvmpipe" to override.
33848b8605Smrg *
34848b8605Smrg * With softpipe we could render directly into the user's buffer by using a
35b8e80941Smrg * display target resource.  However, softpipe doesn't support "upside-down"
36848b8605Smrg * rendering which would be needed for the OSMESA_Y_UP=TRUE case.
37848b8605Smrg *
38848b8605Smrg * With llvmpipe we could only render directly into the user's buffer when its
39848b8605Smrg * width and height is a multiple of the tile size (64 pixels).
40848b8605Smrg *
41848b8605Smrg * Because of these constraints we always render into ordinary resources then
42848b8605Smrg * copy the results to the user's buffer in the flush_front() function which
43848b8605Smrg * is called when the app calls glFlush/Finish.
44848b8605Smrg *
45848b8605Smrg * In general, the OSMesa interface is pretty ugly and not a good match
46848b8605Smrg * for Gallium.  But we're interested in doing the best we can to preserve
47848b8605Smrg * application portability.  With a little work we could come up with a
48848b8605Smrg * much nicer, new off-screen Gallium interface...
49848b8605Smrg */
50848b8605Smrg
51848b8605Smrg
52b8e80941Smrg#include <stdio.h>
53848b8605Smrg#include "GL/osmesa.h"
54848b8605Smrg
55848b8605Smrg#include "glapi/glapi.h"  /* for OSMesaGetProcAddress below */
56848b8605Smrg
57848b8605Smrg#include "pipe/p_context.h"
58848b8605Smrg#include "pipe/p_screen.h"
59848b8605Smrg#include "pipe/p_state.h"
60848b8605Smrg
61848b8605Smrg#include "util/u_atomic.h"
62848b8605Smrg#include "util/u_box.h"
63848b8605Smrg#include "util/u_debug.h"
64848b8605Smrg#include "util/u_format.h"
65b8e80941Smrg#include "util/u_inlines.h"
66848b8605Smrg#include "util/u_memory.h"
67848b8605Smrg
68848b8605Smrg#include "postprocess/filters.h"
69848b8605Smrg#include "postprocess/postprocess.h"
70848b8605Smrg
71848b8605Smrg#include "state_tracker/st_api.h"
72848b8605Smrg#include "state_tracker/st_gl_api.h"
73848b8605Smrg
74848b8605Smrg
75848b8605Smrg
76848b8605Smrgextern struct pipe_screen *
77848b8605Smrgosmesa_create_screen(void);
78848b8605Smrg
79848b8605Smrg
80848b8605Smrg
81848b8605Smrgstruct osmesa_buffer
82848b8605Smrg{
83848b8605Smrg   struct st_framebuffer_iface *stfb;
84848b8605Smrg   struct st_visual visual;
85848b8605Smrg   unsigned width, height;
86848b8605Smrg
87848b8605Smrg   struct pipe_resource *textures[ST_ATTACHMENT_COUNT];
88848b8605Smrg
89848b8605Smrg   void *map;
90848b8605Smrg
91848b8605Smrg   struct osmesa_buffer *next;  /**< next in linked list */
92848b8605Smrg};
93848b8605Smrg
94848b8605Smrg
95848b8605Smrgstruct osmesa_context
96848b8605Smrg{
97848b8605Smrg   struct st_context_iface *stctx;
98848b8605Smrg
99848b8605Smrg   boolean ever_used;     /*< Has this context ever been current? */
100848b8605Smrg
101848b8605Smrg   struct osmesa_buffer *current_buffer;
102848b8605Smrg
103848b8605Smrg   enum pipe_format depth_stencil_format, accum_format;
104848b8605Smrg
105848b8605Smrg   GLenum format;         /*< User-specified context format */
106848b8605Smrg   GLenum type;           /*< Buffer's data type */
107848b8605Smrg   GLint user_row_length; /*< user-specified number of pixels per row */
108848b8605Smrg   GLboolean y_up;        /*< TRUE  -> Y increases upward */
109848b8605Smrg                          /*< FALSE -> Y increases downward */
110848b8605Smrg
111848b8605Smrg   /** Which postprocessing filters are enabled. */
112848b8605Smrg   unsigned pp_enabled[PP_FILTERS];
113848b8605Smrg   struct pp_queue_t *pp;
114848b8605Smrg};
115848b8605Smrg
116848b8605Smrg
117848b8605Smrg/**
118848b8605Smrg * Linked list of all osmesa_buffers.
119848b8605Smrg * We can re-use an osmesa_buffer from one OSMesaMakeCurrent() call to
120848b8605Smrg * the next unless the color/depth/stencil/accum formats change.
121848b8605Smrg * We have to do this to be compatible with the original OSMesa implementation
122848b8605Smrg * because some apps call OSMesaMakeCurrent() several times during rendering
123848b8605Smrg * a frame.
124848b8605Smrg */
125848b8605Smrgstatic struct osmesa_buffer *BufferList = NULL;
126848b8605Smrg
127848b8605Smrg
128848b8605Smrg/**
129848b8605Smrg * Called from the ST manager.
130848b8605Smrg */
131848b8605Smrgstatic int
132848b8605Smrgosmesa_st_get_param(struct st_manager *smapi, enum st_manager_param param)
133848b8605Smrg{
134848b8605Smrg   /* no-op */
135848b8605Smrg   return 0;
136848b8605Smrg}
137848b8605Smrg
138848b8605Smrg
139848b8605Smrg/**
140848b8605Smrg * Create/return singleton st_api object.
141848b8605Smrg */
142848b8605Smrgstatic struct st_api *
143848b8605Smrgget_st_api(void)
144848b8605Smrg{
145848b8605Smrg   static struct st_api *stapi = NULL;
146848b8605Smrg   if (!stapi) {
147848b8605Smrg      stapi = st_gl_api_create();
148848b8605Smrg   }
149848b8605Smrg   return stapi;
150848b8605Smrg}
151848b8605Smrg
152848b8605Smrg
153848b8605Smrg/**
154848b8605Smrg * Create/return a singleton st_manager object.
155848b8605Smrg */
156848b8605Smrgstatic struct st_manager *
157848b8605Smrgget_st_manager(void)
158848b8605Smrg{
159848b8605Smrg   static struct st_manager *stmgr = NULL;
160848b8605Smrg   if (!stmgr) {
161848b8605Smrg      stmgr = CALLOC_STRUCT(st_manager);
162848b8605Smrg      if (stmgr) {
163848b8605Smrg         stmgr->screen = osmesa_create_screen();
164848b8605Smrg         stmgr->get_param = osmesa_st_get_param;
165848b8605Smrg         stmgr->get_egl_image = NULL;
166848b8605Smrg      }
167848b8605Smrg   }
168848b8605Smrg   return stmgr;
169848b8605Smrg}
170848b8605Smrg
171848b8605Smrg
172b8e80941Smrgstatic inline boolean
173848b8605Smrglittle_endian(void)
174848b8605Smrg{
175848b8605Smrg   const unsigned ui = 1;
176848b8605Smrg   return *((const char *) &ui);
177848b8605Smrg}
178848b8605Smrg
179848b8605Smrg
180848b8605Smrg/**
181848b8605Smrg * Given an OSMESA_x format and a GL_y type, return the best
182848b8605Smrg * matching PIPE_FORMAT_z.
183848b8605Smrg * Note that we can't exactly match all user format/type combinations
184848b8605Smrg * with gallium formats.  If we find this to be a problem, we can
185848b8605Smrg * implement more elaborate format/type conversion in the flush_front()
186848b8605Smrg * function.
187848b8605Smrg */
188848b8605Smrgstatic enum pipe_format
189848b8605Smrgosmesa_choose_format(GLenum format, GLenum type)
190848b8605Smrg{
191848b8605Smrg   switch (format) {
192848b8605Smrg   case OSMESA_RGBA:
193848b8605Smrg      if (type == GL_UNSIGNED_BYTE) {
194848b8605Smrg         if (little_endian())
195848b8605Smrg            return PIPE_FORMAT_R8G8B8A8_UNORM;
196848b8605Smrg         else
197848b8605Smrg            return PIPE_FORMAT_A8B8G8R8_UNORM;
198848b8605Smrg      }
199848b8605Smrg      else if (type == GL_UNSIGNED_SHORT) {
200848b8605Smrg         return PIPE_FORMAT_R16G16B16A16_UNORM;
201848b8605Smrg      }
202848b8605Smrg      else if (type == GL_FLOAT) {
203848b8605Smrg         return PIPE_FORMAT_R32G32B32A32_FLOAT;
204848b8605Smrg      }
205848b8605Smrg      else {
206848b8605Smrg         return PIPE_FORMAT_NONE;
207848b8605Smrg      }
208848b8605Smrg      break;
209848b8605Smrg   case OSMESA_BGRA:
210848b8605Smrg      if (type == GL_UNSIGNED_BYTE) {
211848b8605Smrg         if (little_endian())
212848b8605Smrg            return PIPE_FORMAT_B8G8R8A8_UNORM;
213848b8605Smrg         else
214848b8605Smrg            return PIPE_FORMAT_A8R8G8B8_UNORM;
215848b8605Smrg      }
216848b8605Smrg      else if (type == GL_UNSIGNED_SHORT) {
217848b8605Smrg         return PIPE_FORMAT_R16G16B16A16_UNORM;
218848b8605Smrg      }
219848b8605Smrg      else if (type == GL_FLOAT) {
220848b8605Smrg         return PIPE_FORMAT_R32G32B32A32_FLOAT;
221848b8605Smrg      }
222848b8605Smrg      else {
223848b8605Smrg         return PIPE_FORMAT_NONE;
224848b8605Smrg      }
225848b8605Smrg      break;
226848b8605Smrg   case OSMESA_ARGB:
227848b8605Smrg      if (type == GL_UNSIGNED_BYTE) {
228848b8605Smrg         if (little_endian())
229848b8605Smrg            return PIPE_FORMAT_A8R8G8B8_UNORM;
230848b8605Smrg         else
231848b8605Smrg            return PIPE_FORMAT_B8G8R8A8_UNORM;
232848b8605Smrg      }
233848b8605Smrg      else if (type == GL_UNSIGNED_SHORT) {
234848b8605Smrg         return PIPE_FORMAT_R16G16B16A16_UNORM;
235848b8605Smrg      }
236848b8605Smrg      else if (type == GL_FLOAT) {
237848b8605Smrg         return PIPE_FORMAT_R32G32B32A32_FLOAT;
238848b8605Smrg      }
239848b8605Smrg      else {
240848b8605Smrg         return PIPE_FORMAT_NONE;
241848b8605Smrg      }
242848b8605Smrg      break;
243848b8605Smrg   case OSMESA_RGB:
244848b8605Smrg      if (type == GL_UNSIGNED_BYTE) {
245848b8605Smrg         return PIPE_FORMAT_R8G8B8_UNORM;
246848b8605Smrg      }
247848b8605Smrg      else if (type == GL_UNSIGNED_SHORT) {
248848b8605Smrg         return PIPE_FORMAT_R16G16B16_UNORM;
249848b8605Smrg      }
250848b8605Smrg      else if (type == GL_FLOAT) {
251848b8605Smrg         return PIPE_FORMAT_R32G32B32_FLOAT;
252848b8605Smrg      }
253848b8605Smrg      else {
254848b8605Smrg         return PIPE_FORMAT_NONE;
255848b8605Smrg      }
256848b8605Smrg      break;
257848b8605Smrg   case OSMESA_BGR:
258848b8605Smrg      /* No gallium format for this one */
259848b8605Smrg      return PIPE_FORMAT_NONE;
260848b8605Smrg   case OSMESA_RGB_565:
261848b8605Smrg      return PIPE_FORMAT_B5G6R5_UNORM;
262848b8605Smrg   default:
263848b8605Smrg      ; /* fall-through */
264848b8605Smrg   }
265848b8605Smrg   return PIPE_FORMAT_NONE;
266848b8605Smrg}
267848b8605Smrg
268848b8605Smrg
269848b8605Smrg/**
270848b8605Smrg * Initialize an st_visual object.
271848b8605Smrg */
272848b8605Smrgstatic void
273848b8605Smrgosmesa_init_st_visual(struct st_visual *vis,
274848b8605Smrg                      enum pipe_format color_format,
275848b8605Smrg                      enum pipe_format ds_format,
276848b8605Smrg                      enum pipe_format accum_format)
277848b8605Smrg{
278848b8605Smrg   vis->buffer_mask = ST_ATTACHMENT_FRONT_LEFT_MASK;
279848b8605Smrg
280848b8605Smrg   if (ds_format != PIPE_FORMAT_NONE)
281848b8605Smrg      vis->buffer_mask |= ST_ATTACHMENT_DEPTH_STENCIL_MASK;
282848b8605Smrg   if (accum_format != PIPE_FORMAT_NONE)
283848b8605Smrg      vis->buffer_mask |= ST_ATTACHMENT_ACCUM;
284848b8605Smrg
285848b8605Smrg   vis->color_format = color_format;
286848b8605Smrg   vis->depth_stencil_format = ds_format;
287848b8605Smrg   vis->accum_format = accum_format;
288848b8605Smrg   vis->samples = 1;
289848b8605Smrg   vis->render_buffer = ST_ATTACHMENT_FRONT_LEFT;
290848b8605Smrg}
291848b8605Smrg
292848b8605Smrg
293848b8605Smrg/**
294848b8605Smrg * Return the osmesa_buffer that corresponds to an st_framebuffer_iface.
295848b8605Smrg */
296b8e80941Smrgstatic inline struct osmesa_buffer *
297848b8605Smrgstfbi_to_osbuffer(struct st_framebuffer_iface *stfbi)
298848b8605Smrg{
299848b8605Smrg   return (struct osmesa_buffer *) stfbi->st_manager_private;
300848b8605Smrg}
301848b8605Smrg
302848b8605Smrg
303848b8605Smrg/**
304848b8605Smrg * Called via glFlush/glFinish.  This is where we copy the contents
305848b8605Smrg * of the driver's color buffer into the user-specified buffer.
306848b8605Smrg */
307848b8605Smrgstatic boolean
308848b8605Smrgosmesa_st_framebuffer_flush_front(struct st_context_iface *stctx,
309848b8605Smrg                                  struct st_framebuffer_iface *stfbi,
310848b8605Smrg                                  enum st_attachment_type statt)
311848b8605Smrg{
312848b8605Smrg   OSMesaContext osmesa = OSMesaGetCurrentContext();
313848b8605Smrg   struct osmesa_buffer *osbuffer = stfbi_to_osbuffer(stfbi);
314848b8605Smrg   struct pipe_context *pipe = stctx->pipe;
315848b8605Smrg   struct pipe_resource *res = osbuffer->textures[statt];
316848b8605Smrg   struct pipe_transfer *transfer = NULL;
317848b8605Smrg   struct pipe_box box;
318848b8605Smrg   void *map;
319848b8605Smrg   ubyte *src, *dst;
320848b8605Smrg   unsigned y, bytes, bpp;
321848b8605Smrg   int dst_stride;
322848b8605Smrg
323848b8605Smrg   if (osmesa->pp) {
324848b8605Smrg      struct pipe_resource *zsbuf = NULL;
325848b8605Smrg      unsigned i;
326848b8605Smrg
327848b8605Smrg      /* Find the z/stencil buffer if there is one */
328b8e80941Smrg      for (i = 0; i < ARRAY_SIZE(osbuffer->textures); i++) {
329848b8605Smrg         struct pipe_resource *res = osbuffer->textures[i];
330848b8605Smrg         if (res) {
331848b8605Smrg            const struct util_format_description *desc =
332848b8605Smrg               util_format_description(res->format);
333848b8605Smrg
334848b8605Smrg            if (util_format_has_depth(desc)) {
335848b8605Smrg               zsbuf = res;
336848b8605Smrg               break;
337848b8605Smrg            }
338848b8605Smrg         }
339848b8605Smrg      }
340848b8605Smrg
341848b8605Smrg      /* run the postprocess stage(s) */
342848b8605Smrg      pp_run(osmesa->pp, res, res, zsbuf);
343848b8605Smrg   }
344848b8605Smrg
345848b8605Smrg   u_box_2d(0, 0, res->width0, res->height0, &box);
346848b8605Smrg
347848b8605Smrg   map = pipe->transfer_map(pipe, res, 0, PIPE_TRANSFER_READ, &box,
348848b8605Smrg                            &transfer);
349848b8605Smrg
350848b8605Smrg   /*
351848b8605Smrg    * Copy the color buffer from the resource to the user's buffer.
352848b8605Smrg    */
353848b8605Smrg   bpp = util_format_get_blocksize(osbuffer->visual.color_format);
354848b8605Smrg   src = map;
355848b8605Smrg   dst = osbuffer->map;
356848b8605Smrg   if (osmesa->user_row_length)
357848b8605Smrg      dst_stride = bpp * osmesa->user_row_length;
358848b8605Smrg   else
359848b8605Smrg      dst_stride = bpp * osbuffer->width;
360848b8605Smrg   bytes = bpp * res->width0;
361848b8605Smrg
362848b8605Smrg   if (osmesa->y_up) {
363848b8605Smrg      /* need to flip image upside down */
364848b8605Smrg      dst = dst + (res->height0 - 1) * dst_stride;
365848b8605Smrg      dst_stride = -dst_stride;
366848b8605Smrg   }
367848b8605Smrg
368848b8605Smrg   for (y = 0; y < res->height0; y++) {
369848b8605Smrg      memcpy(dst, src, bytes);
370848b8605Smrg      dst += dst_stride;
371848b8605Smrg      src += transfer->stride;
372848b8605Smrg   }
373848b8605Smrg
374848b8605Smrg   pipe->transfer_unmap(pipe, transfer);
375848b8605Smrg
376848b8605Smrg   return TRUE;
377848b8605Smrg}
378848b8605Smrg
379848b8605Smrg
380848b8605Smrg/**
381848b8605Smrg * Called by the st manager to validate the framebuffer (allocate
382848b8605Smrg * its resources).
383848b8605Smrg */
384848b8605Smrgstatic boolean
385848b8605Smrgosmesa_st_framebuffer_validate(struct st_context_iface *stctx,
386848b8605Smrg                               struct st_framebuffer_iface *stfbi,
387848b8605Smrg                               const enum st_attachment_type *statts,
388848b8605Smrg                               unsigned count,
389848b8605Smrg                               struct pipe_resource **out)
390848b8605Smrg{
391848b8605Smrg   struct pipe_screen *screen = get_st_manager()->screen;
392848b8605Smrg   enum st_attachment_type i;
393848b8605Smrg   struct osmesa_buffer *osbuffer = stfbi_to_osbuffer(stfbi);
394848b8605Smrg   struct pipe_resource templat;
395848b8605Smrg
396848b8605Smrg   memset(&templat, 0, sizeof(templat));
397848b8605Smrg   templat.target = PIPE_TEXTURE_RECT;
398848b8605Smrg   templat.format = 0; /* setup below */
399848b8605Smrg   templat.last_level = 0;
400848b8605Smrg   templat.width0 = osbuffer->width;
401848b8605Smrg   templat.height0 = osbuffer->height;
402848b8605Smrg   templat.depth0 = 1;
403848b8605Smrg   templat.array_size = 1;
404848b8605Smrg   templat.usage = PIPE_USAGE_DEFAULT;
405848b8605Smrg   templat.bind = 0; /* setup below */
406848b8605Smrg   templat.flags = 0;
407848b8605Smrg
408848b8605Smrg   for (i = 0; i < count; i++) {
409848b8605Smrg      enum pipe_format format = PIPE_FORMAT_NONE;
410848b8605Smrg      unsigned bind = 0;
411848b8605Smrg
412848b8605Smrg      /*
413848b8605Smrg       * At this time, we really only need to handle the front-left color
414848b8605Smrg       * attachment, since that's all we specified for the visual in
415848b8605Smrg       * osmesa_init_st_visual().
416848b8605Smrg       */
417848b8605Smrg      if (statts[i] == ST_ATTACHMENT_FRONT_LEFT) {
418848b8605Smrg         format = osbuffer->visual.color_format;
419848b8605Smrg         bind = PIPE_BIND_RENDER_TARGET;
420848b8605Smrg      }
421848b8605Smrg      else if (statts[i] == ST_ATTACHMENT_DEPTH_STENCIL) {
422848b8605Smrg         format = osbuffer->visual.depth_stencil_format;
423848b8605Smrg         bind = PIPE_BIND_DEPTH_STENCIL;
424848b8605Smrg      }
425848b8605Smrg      else if (statts[i] == ST_ATTACHMENT_ACCUM) {
426848b8605Smrg         format = osbuffer->visual.accum_format;
427848b8605Smrg         bind = PIPE_BIND_RENDER_TARGET;
428848b8605Smrg      }
429848b8605Smrg      else {
430848b8605Smrg         debug_warning("Unexpected attachment type in "
431848b8605Smrg                       "osmesa_st_framebuffer_validate()");
432848b8605Smrg      }
433848b8605Smrg
434848b8605Smrg      templat.format = format;
435848b8605Smrg      templat.bind = bind;
436b8e80941Smrg      pipe_resource_reference(&out[i], NULL);
437b8e80941Smrg      out[i] = osbuffer->textures[statts[i]] =
438848b8605Smrg         screen->resource_create(screen, &templat);
439848b8605Smrg   }
440848b8605Smrg
441848b8605Smrg   return TRUE;
442848b8605Smrg}
443848b8605Smrg
444b8e80941Smrgstatic uint32_t osmesa_fb_ID = 0;
445848b8605Smrg
446848b8605Smrgstatic struct st_framebuffer_iface *
447848b8605Smrgosmesa_create_st_framebuffer(void)
448848b8605Smrg{
449848b8605Smrg   struct st_framebuffer_iface *stfbi = CALLOC_STRUCT(st_framebuffer_iface);
450848b8605Smrg   if (stfbi) {
451848b8605Smrg      stfbi->flush_front = osmesa_st_framebuffer_flush_front;
452848b8605Smrg      stfbi->validate = osmesa_st_framebuffer_validate;
453848b8605Smrg      p_atomic_set(&stfbi->stamp, 1);
454b8e80941Smrg      stfbi->ID = p_atomic_inc_return(&osmesa_fb_ID);
455b8e80941Smrg      stfbi->state_manager = get_st_manager();
456848b8605Smrg   }
457848b8605Smrg   return stfbi;
458848b8605Smrg}
459848b8605Smrg
460848b8605Smrg
461848b8605Smrg/**
462848b8605Smrg * Create new buffer and add to linked list.
463848b8605Smrg */
464848b8605Smrgstatic struct osmesa_buffer *
465848b8605Smrgosmesa_create_buffer(enum pipe_format color_format,
466848b8605Smrg                     enum pipe_format ds_format,
467848b8605Smrg                     enum pipe_format accum_format)
468848b8605Smrg{
469848b8605Smrg   struct osmesa_buffer *osbuffer = CALLOC_STRUCT(osmesa_buffer);
470848b8605Smrg   if (osbuffer) {
471848b8605Smrg      osbuffer->stfb = osmesa_create_st_framebuffer();
472848b8605Smrg
473848b8605Smrg      osbuffer->stfb->st_manager_private = osbuffer;
474848b8605Smrg      osbuffer->stfb->visual = &osbuffer->visual;
475848b8605Smrg
476848b8605Smrg      osmesa_init_st_visual(&osbuffer->visual, color_format,
477848b8605Smrg                            ds_format, accum_format);
478848b8605Smrg
479848b8605Smrg      /* insert into linked list */
480848b8605Smrg      osbuffer->next = BufferList;
481848b8605Smrg      BufferList = osbuffer;
482848b8605Smrg   }
483848b8605Smrg
484848b8605Smrg   return osbuffer;
485848b8605Smrg}
486848b8605Smrg
487848b8605Smrg
488848b8605Smrg/**
489848b8605Smrg * Search linked list for a buffer with matching pixel formats and size.
490848b8605Smrg */
491848b8605Smrgstatic struct osmesa_buffer *
492848b8605Smrgosmesa_find_buffer(enum pipe_format color_format,
493848b8605Smrg                   enum pipe_format ds_format,
494848b8605Smrg                   enum pipe_format accum_format,
495848b8605Smrg                   GLsizei width, GLsizei height)
496848b8605Smrg{
497848b8605Smrg   struct osmesa_buffer *b;
498848b8605Smrg
499848b8605Smrg   /* Check if we already have a suitable buffer for the given formats */
500848b8605Smrg   for (b = BufferList; b; b = b->next) {
501848b8605Smrg      if (b->visual.color_format == color_format &&
502848b8605Smrg          b->visual.depth_stencil_format == ds_format &&
503848b8605Smrg          b->visual.accum_format == accum_format &&
504848b8605Smrg          b->width == width &&
505848b8605Smrg          b->height == height) {
506848b8605Smrg         return b;
507848b8605Smrg      }
508848b8605Smrg   }
509848b8605Smrg   return NULL;
510848b8605Smrg}
511848b8605Smrg
512848b8605Smrg
513848b8605Smrgstatic void
514848b8605Smrgosmesa_destroy_buffer(struct osmesa_buffer *osbuffer)
515848b8605Smrg{
516b8e80941Smrg   struct st_api *stapi = get_st_api();
517b8e80941Smrg
518b8e80941Smrg   /*
519b8e80941Smrg    * Notify the state manager that the associated framebuffer interface
520b8e80941Smrg    * is no longer valid.
521b8e80941Smrg    */
522b8e80941Smrg   stapi->destroy_drawable(stapi, osbuffer->stfb);
523b8e80941Smrg
524848b8605Smrg   FREE(osbuffer->stfb);
525848b8605Smrg   FREE(osbuffer);
526848b8605Smrg}
527848b8605Smrg
528848b8605Smrg
529848b8605Smrg
530848b8605Smrg/**********************************************************************/
531848b8605Smrg/*****                    Public Functions                        *****/
532848b8605Smrg/**********************************************************************/
533848b8605Smrg
534848b8605Smrg
535848b8605Smrg/**
536848b8605Smrg * Create an Off-Screen Mesa rendering context.  The only attribute needed is
537848b8605Smrg * an RGBA vs Color-Index mode flag.
538848b8605Smrg *
539848b8605Smrg * Input:  format - Must be GL_RGBA
540848b8605Smrg *         sharelist - specifies another OSMesaContext with which to share
541848b8605Smrg *                     display lists.  NULL indicates no sharing.
542848b8605Smrg * Return:  an OSMesaContext or 0 if error
543848b8605Smrg */
544848b8605SmrgGLAPI OSMesaContext GLAPIENTRY
545848b8605SmrgOSMesaCreateContext(GLenum format, OSMesaContext sharelist)
546848b8605Smrg{
547848b8605Smrg   return OSMesaCreateContextExt(format, 24, 8, 0, sharelist);
548848b8605Smrg}
549848b8605Smrg
550848b8605Smrg
551848b8605Smrg/**
552848b8605Smrg * New in Mesa 3.5
553848b8605Smrg *
554848b8605Smrg * Create context and specify size of ancillary buffers.
555848b8605Smrg */
556848b8605SmrgGLAPI OSMesaContext GLAPIENTRY
557848b8605SmrgOSMesaCreateContextExt(GLenum format, GLint depthBits, GLint stencilBits,
558848b8605Smrg                       GLint accumBits, OSMesaContext sharelist)
559b8e80941Smrg{
560b8e80941Smrg   int attribs[100], n = 0;
561b8e80941Smrg
562b8e80941Smrg   attribs[n++] = OSMESA_FORMAT;
563b8e80941Smrg   attribs[n++] = format;
564b8e80941Smrg   attribs[n++] = OSMESA_DEPTH_BITS;
565b8e80941Smrg   attribs[n++] = depthBits;
566b8e80941Smrg   attribs[n++] = OSMESA_STENCIL_BITS;
567b8e80941Smrg   attribs[n++] = stencilBits;
568b8e80941Smrg   attribs[n++] = OSMESA_ACCUM_BITS;
569b8e80941Smrg   attribs[n++] = accumBits;
570b8e80941Smrg   attribs[n++] = 0;
571b8e80941Smrg
572b8e80941Smrg   return OSMesaCreateContextAttribs(attribs, sharelist);
573b8e80941Smrg}
574b8e80941Smrg
575b8e80941Smrg
576b8e80941Smrg/**
577b8e80941Smrg * New in Mesa 11.2
578b8e80941Smrg *
579b8e80941Smrg * Create context with attribute list.
580b8e80941Smrg */
581b8e80941SmrgGLAPI OSMesaContext GLAPIENTRY
582b8e80941SmrgOSMesaCreateContextAttribs(const int *attribList, OSMesaContext sharelist)
583848b8605Smrg{
584848b8605Smrg   OSMesaContext osmesa;
585848b8605Smrg   struct st_context_iface *st_shared;
586848b8605Smrg   enum st_context_error st_error = 0;
587848b8605Smrg   struct st_context_attribs attribs;
588848b8605Smrg   struct st_api *stapi = get_st_api();
589b8e80941Smrg   GLenum format = GL_RGBA;
590b8e80941Smrg   int depthBits = 0, stencilBits = 0, accumBits = 0;
591b8e80941Smrg   int profile = OSMESA_COMPAT_PROFILE, version_major = 1, version_minor = 0;
592b8e80941Smrg   int i;
593848b8605Smrg
594848b8605Smrg   if (sharelist) {
595848b8605Smrg      st_shared = sharelist->stctx;
596848b8605Smrg   }
597848b8605Smrg   else {
598848b8605Smrg      st_shared = NULL;
599848b8605Smrg   }
600848b8605Smrg
601b8e80941Smrg   for (i = 0; attribList[i]; i += 2) {
602b8e80941Smrg      switch (attribList[i]) {
603b8e80941Smrg      case OSMESA_FORMAT:
604b8e80941Smrg         format = attribList[i+1];
605b8e80941Smrg         switch (format) {
606b8e80941Smrg         case OSMESA_COLOR_INDEX:
607b8e80941Smrg         case OSMESA_RGBA:
608b8e80941Smrg         case OSMESA_BGRA:
609b8e80941Smrg         case OSMESA_ARGB:
610b8e80941Smrg         case OSMESA_RGB:
611b8e80941Smrg         case OSMESA_BGR:
612b8e80941Smrg         case OSMESA_RGB_565:
613b8e80941Smrg            /* legal */
614b8e80941Smrg            break;
615b8e80941Smrg         default:
616b8e80941Smrg            return NULL;
617b8e80941Smrg         }
618b8e80941Smrg         break;
619b8e80941Smrg      case OSMESA_DEPTH_BITS:
620b8e80941Smrg         depthBits = attribList[i+1];
621b8e80941Smrg         if (depthBits < 0)
622b8e80941Smrg            return NULL;
623b8e80941Smrg         break;
624b8e80941Smrg      case OSMESA_STENCIL_BITS:
625b8e80941Smrg         stencilBits = attribList[i+1];
626b8e80941Smrg         if (stencilBits < 0)
627b8e80941Smrg            return NULL;
628b8e80941Smrg         break;
629b8e80941Smrg      case OSMESA_ACCUM_BITS:
630b8e80941Smrg         accumBits = attribList[i+1];
631b8e80941Smrg         if (accumBits < 0)
632b8e80941Smrg            return NULL;
633b8e80941Smrg         break;
634b8e80941Smrg      case OSMESA_PROFILE:
635b8e80941Smrg         profile = attribList[i+1];
636b8e80941Smrg         if (profile != OSMESA_CORE_PROFILE &&
637b8e80941Smrg             profile != OSMESA_COMPAT_PROFILE)
638b8e80941Smrg            return NULL;
639b8e80941Smrg         break;
640b8e80941Smrg      case OSMESA_CONTEXT_MAJOR_VERSION:
641b8e80941Smrg         version_major = attribList[i+1];
642b8e80941Smrg         if (version_major < 1)
643b8e80941Smrg            return NULL;
644b8e80941Smrg         break;
645b8e80941Smrg      case OSMESA_CONTEXT_MINOR_VERSION:
646b8e80941Smrg         version_minor = attribList[i+1];
647b8e80941Smrg         if (version_minor < 0)
648b8e80941Smrg            return NULL;
649b8e80941Smrg         break;
650b8e80941Smrg      case 0:
651b8e80941Smrg         /* end of list */
652b8e80941Smrg         break;
653b8e80941Smrg      default:
654b8e80941Smrg         fprintf(stderr, "Bad attribute in OSMesaCreateContextAttribs()\n");
655b8e80941Smrg         return NULL;
656b8e80941Smrg      }
657b8e80941Smrg   }
658b8e80941Smrg
659848b8605Smrg   osmesa = (OSMesaContext) CALLOC_STRUCT(osmesa_context);
660848b8605Smrg   if (!osmesa)
661848b8605Smrg      return NULL;
662848b8605Smrg
663848b8605Smrg   /* Choose depth/stencil/accum buffer formats */
664848b8605Smrg   if (accumBits > 0) {
665848b8605Smrg      osmesa->accum_format = PIPE_FORMAT_R16G16B16A16_SNORM;
666848b8605Smrg   }
667848b8605Smrg   if (depthBits > 0 && stencilBits > 0) {
668848b8605Smrg      osmesa->depth_stencil_format = PIPE_FORMAT_Z24_UNORM_S8_UINT;
669848b8605Smrg   }
670848b8605Smrg   else if (stencilBits > 0) {
671848b8605Smrg      osmesa->depth_stencil_format = PIPE_FORMAT_S8_UINT;
672848b8605Smrg   }
673848b8605Smrg   else if (depthBits >= 24) {
674848b8605Smrg      osmesa->depth_stencil_format = PIPE_FORMAT_Z24X8_UNORM;
675848b8605Smrg   }
676848b8605Smrg   else if (depthBits >= 16) {
677848b8605Smrg      osmesa->depth_stencil_format = PIPE_FORMAT_Z16_UNORM;
678848b8605Smrg   }
679848b8605Smrg
680848b8605Smrg   /*
681848b8605Smrg    * Create the rendering context
682848b8605Smrg    */
683b8e80941Smrg   memset(&attribs, 0, sizeof(attribs));
684b8e80941Smrg   attribs.profile = (profile == OSMESA_CORE_PROFILE)
685b8e80941Smrg      ? ST_PROFILE_OPENGL_CORE : ST_PROFILE_DEFAULT;
686b8e80941Smrg   attribs.major = version_major;
687b8e80941Smrg   attribs.minor = version_minor;
688848b8605Smrg   attribs.flags = 0;  /* ST_CONTEXT_FLAG_x */
689848b8605Smrg   attribs.options.force_glsl_extensions_warn = FALSE;
690848b8605Smrg   attribs.options.disable_blend_func_extended = FALSE;
691848b8605Smrg   attribs.options.disable_glsl_line_continuations = FALSE;
692848b8605Smrg   attribs.options.force_glsl_version = 0;
693848b8605Smrg
694848b8605Smrg   osmesa_init_st_visual(&attribs.visual,
695848b8605Smrg                         PIPE_FORMAT_R8G8B8A8_UNORM,
696848b8605Smrg                         osmesa->depth_stencil_format,
697848b8605Smrg                         osmesa->accum_format);
698848b8605Smrg
699848b8605Smrg   osmesa->stctx = stapi->create_context(stapi, get_st_manager(),
700848b8605Smrg                                         &attribs, &st_error, st_shared);
701848b8605Smrg   if (!osmesa->stctx) {
702848b8605Smrg      FREE(osmesa);
703848b8605Smrg      return NULL;
704848b8605Smrg   }
705848b8605Smrg
706848b8605Smrg   osmesa->stctx->st_manager_private = osmesa;
707848b8605Smrg
708848b8605Smrg   osmesa->format = format;
709848b8605Smrg   osmesa->user_row_length = 0;
710848b8605Smrg   osmesa->y_up = GL_TRUE;
711848b8605Smrg
712848b8605Smrg   return osmesa;
713848b8605Smrg}
714848b8605Smrg
715848b8605Smrg
716b8e80941Smrg
717848b8605Smrg/**
718848b8605Smrg * Destroy an Off-Screen Mesa rendering context.
719848b8605Smrg *
720848b8605Smrg * \param osmesa  the context to destroy
721848b8605Smrg */
722848b8605SmrgGLAPI void GLAPIENTRY
723848b8605SmrgOSMesaDestroyContext(OSMesaContext osmesa)
724848b8605Smrg{
725848b8605Smrg   if (osmesa) {
726848b8605Smrg      pp_free(osmesa->pp);
727848b8605Smrg      osmesa->stctx->destroy(osmesa->stctx);
728848b8605Smrg      FREE(osmesa);
729848b8605Smrg   }
730848b8605Smrg}
731848b8605Smrg
732848b8605Smrg
733848b8605Smrg/**
734848b8605Smrg * Bind an OSMesaContext to an image buffer.  The image buffer is just a
735848b8605Smrg * block of memory which the client provides.  Its size must be at least
736848b8605Smrg * as large as width*height*pixelSize.  Its address should be a multiple
737848b8605Smrg * of 4 if using RGBA mode.
738848b8605Smrg *
739848b8605Smrg * By default, image data is stored in the order of glDrawPixels: row-major
740848b8605Smrg * order with the lower-left image pixel stored in the first array position
741848b8605Smrg * (ie. bottom-to-top).
742848b8605Smrg *
743848b8605Smrg * If the context's viewport hasn't been initialized yet, it will now be
744848b8605Smrg * initialized to (0,0,width,height).
745848b8605Smrg *
746848b8605Smrg * Input:  osmesa - the rendering context
747848b8605Smrg *         buffer - the image buffer memory
748848b8605Smrg *         type - data type for pixel components
749848b8605Smrg *                GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_SHORT
750848b8605Smrg *                or GL_FLOAT.
751848b8605Smrg *         width, height - size of image buffer in pixels, at least 1
752848b8605Smrg * Return:  GL_TRUE if success, GL_FALSE if error because of invalid osmesa,
753848b8605Smrg *          invalid type, invalid size, etc.
754848b8605Smrg */
755848b8605SmrgGLAPI GLboolean GLAPIENTRY
756848b8605SmrgOSMesaMakeCurrent(OSMesaContext osmesa, void *buffer, GLenum type,
757848b8605Smrg                  GLsizei width, GLsizei height)
758848b8605Smrg{
759848b8605Smrg   struct st_api *stapi = get_st_api();
760848b8605Smrg   struct osmesa_buffer *osbuffer;
761848b8605Smrg   enum pipe_format color_format;
762848b8605Smrg
763848b8605Smrg   if (!osmesa || !buffer || width < 1 || height < 1) {
764848b8605Smrg      return GL_FALSE;
765848b8605Smrg   }
766848b8605Smrg
767848b8605Smrg   if (osmesa->format == OSMESA_RGB_565 && type != GL_UNSIGNED_SHORT_5_6_5) {
768848b8605Smrg      return GL_FALSE;
769848b8605Smrg   }
770848b8605Smrg
771848b8605Smrg   color_format = osmesa_choose_format(osmesa->format, type);
772848b8605Smrg   if (color_format == PIPE_FORMAT_NONE) {
773848b8605Smrg      fprintf(stderr, "OSMesaMakeCurrent(unsupported format/type)\n");
774848b8605Smrg      return GL_FALSE;
775848b8605Smrg   }
776848b8605Smrg
777848b8605Smrg   /* See if we already have a buffer that uses these pixel formats */
778848b8605Smrg   osbuffer = osmesa_find_buffer(color_format,
779848b8605Smrg                                 osmesa->depth_stencil_format,
780848b8605Smrg                                 osmesa->accum_format, width, height);
781848b8605Smrg   if (!osbuffer) {
782848b8605Smrg      /* Existing buffer found, create new buffer */
783848b8605Smrg      osbuffer = osmesa_create_buffer(color_format,
784848b8605Smrg                                      osmesa->depth_stencil_format,
785848b8605Smrg                                      osmesa->accum_format);
786848b8605Smrg   }
787848b8605Smrg
788848b8605Smrg   osbuffer->width = width;
789848b8605Smrg   osbuffer->height = height;
790848b8605Smrg   osbuffer->map = buffer;
791848b8605Smrg
792848b8605Smrg   /* XXX unused for now */
793848b8605Smrg   (void) osmesa_destroy_buffer;
794848b8605Smrg
795848b8605Smrg   osmesa->current_buffer = osbuffer;
796848b8605Smrg   osmesa->type = type;
797848b8605Smrg
798848b8605Smrg   stapi->make_current(stapi, osmesa->stctx, osbuffer->stfb, osbuffer->stfb);
799848b8605Smrg
800848b8605Smrg   if (!osmesa->ever_used) {
801848b8605Smrg      /* one-time init, just postprocessing for now */
802848b8605Smrg      boolean any_pp_enabled = FALSE;
803848b8605Smrg      unsigned i;
804848b8605Smrg
805b8e80941Smrg      for (i = 0; i < ARRAY_SIZE(osmesa->pp_enabled); i++) {
806848b8605Smrg         if (osmesa->pp_enabled[i]) {
807848b8605Smrg            any_pp_enabled = TRUE;
808848b8605Smrg            break;
809848b8605Smrg         }
810848b8605Smrg      }
811848b8605Smrg
812848b8605Smrg      if (any_pp_enabled) {
813848b8605Smrg         osmesa->pp = pp_init(osmesa->stctx->pipe,
814848b8605Smrg                              osmesa->pp_enabled,
815848b8605Smrg                              osmesa->stctx->cso_context);
816848b8605Smrg
817848b8605Smrg         pp_init_fbos(osmesa->pp, width, height);
818848b8605Smrg      }
819848b8605Smrg
820848b8605Smrg      osmesa->ever_used = TRUE;
821848b8605Smrg   }
822848b8605Smrg
823848b8605Smrg   return GL_TRUE;
824848b8605Smrg}
825848b8605Smrg
826848b8605Smrg
827848b8605Smrg
828848b8605SmrgGLAPI OSMesaContext GLAPIENTRY
829848b8605SmrgOSMesaGetCurrentContext(void)
830848b8605Smrg{
831848b8605Smrg   struct st_api *stapi = get_st_api();
832848b8605Smrg   struct st_context_iface *st = stapi->get_current(stapi);
833848b8605Smrg   return st ? (OSMesaContext) st->st_manager_private : NULL;
834848b8605Smrg}
835848b8605Smrg
836848b8605Smrg
837848b8605Smrg
838848b8605SmrgGLAPI void GLAPIENTRY
839848b8605SmrgOSMesaPixelStore(GLint pname, GLint value)
840848b8605Smrg{
841848b8605Smrg   OSMesaContext osmesa = OSMesaGetCurrentContext();
842848b8605Smrg
843848b8605Smrg   switch (pname) {
844848b8605Smrg   case OSMESA_ROW_LENGTH:
845848b8605Smrg      osmesa->user_row_length = value;
846848b8605Smrg      break;
847848b8605Smrg   case OSMESA_Y_UP:
848848b8605Smrg      osmesa->y_up = value ? GL_TRUE : GL_FALSE;
849848b8605Smrg      break;
850848b8605Smrg   default:
851848b8605Smrg      fprintf(stderr, "Invalid pname in OSMesaPixelStore()\n");
852848b8605Smrg      return;
853848b8605Smrg   }
854848b8605Smrg}
855848b8605Smrg
856848b8605Smrg
857848b8605SmrgGLAPI void GLAPIENTRY
858848b8605SmrgOSMesaGetIntegerv(GLint pname, GLint *value)
859848b8605Smrg{
860848b8605Smrg   OSMesaContext osmesa = OSMesaGetCurrentContext();
861848b8605Smrg   struct osmesa_buffer *osbuffer = osmesa ? osmesa->current_buffer : NULL;
862848b8605Smrg
863848b8605Smrg   switch (pname) {
864848b8605Smrg   case OSMESA_WIDTH:
865848b8605Smrg      *value = osbuffer ? osbuffer->width : 0;
866848b8605Smrg      return;
867848b8605Smrg   case OSMESA_HEIGHT:
868848b8605Smrg      *value = osbuffer ? osbuffer->height : 0;
869848b8605Smrg      return;
870848b8605Smrg   case OSMESA_FORMAT:
871848b8605Smrg      *value = osmesa->format;
872848b8605Smrg      return;
873848b8605Smrg   case OSMESA_TYPE:
874848b8605Smrg      /* current color buffer's data type */
875848b8605Smrg      *value = osmesa->type;
876848b8605Smrg      return;
877848b8605Smrg   case OSMESA_ROW_LENGTH:
878848b8605Smrg      *value = osmesa->user_row_length;
879848b8605Smrg      return;
880848b8605Smrg   case OSMESA_Y_UP:
881848b8605Smrg      *value = osmesa->y_up;
882848b8605Smrg      return;
883848b8605Smrg   case OSMESA_MAX_WIDTH:
884848b8605Smrg      /* fall-through */
885848b8605Smrg   case OSMESA_MAX_HEIGHT:
886848b8605Smrg      {
887848b8605Smrg         struct pipe_screen *screen = get_st_manager()->screen;
888848b8605Smrg         int maxLevels = screen->get_param(screen,
889848b8605Smrg                                           PIPE_CAP_MAX_TEXTURE_2D_LEVELS);
890848b8605Smrg         *value = 1 << (maxLevels - 1);
891848b8605Smrg      }
892848b8605Smrg      return;
893848b8605Smrg   default:
894848b8605Smrg      fprintf(stderr, "Invalid pname in OSMesaGetIntegerv()\n");
895848b8605Smrg      return;
896848b8605Smrg   }
897848b8605Smrg}
898848b8605Smrg
899848b8605Smrg
900848b8605Smrg/**
901848b8605Smrg * Return information about the depth buffer associated with an OSMesa context.
902848b8605Smrg * Input:  c - the OSMesa context
903848b8605Smrg * Output:  width, height - size of buffer in pixels
904848b8605Smrg *          bytesPerValue - bytes per depth value (2 or 4)
905848b8605Smrg *          buffer - pointer to depth buffer values
906848b8605Smrg * Return:  GL_TRUE or GL_FALSE to indicate success or failure.
907848b8605Smrg */
908848b8605SmrgGLAPI GLboolean GLAPIENTRY
909848b8605SmrgOSMesaGetDepthBuffer(OSMesaContext c, GLint *width, GLint *height,
910848b8605Smrg                     GLint *bytesPerValue, void **buffer)
911848b8605Smrg{
912848b8605Smrg   struct osmesa_buffer *osbuffer = c->current_buffer;
913848b8605Smrg   struct pipe_context *pipe = c->stctx->pipe;
914848b8605Smrg   struct pipe_resource *res = osbuffer->textures[ST_ATTACHMENT_DEPTH_STENCIL];
915848b8605Smrg   struct pipe_transfer *transfer = NULL;
916848b8605Smrg   struct pipe_box box;
917848b8605Smrg
918848b8605Smrg   /*
919848b8605Smrg    * Note: we can't really implement this function with gallium as
920848b8605Smrg    * we did for swrast.  We can't just map the resource and leave it
921848b8605Smrg    * mapped (and there's no OSMesaUnmapDepthBuffer() function) so
922848b8605Smrg    * we unmap the buffer here and return a 'stale' pointer.  This should
923848b8605Smrg    * actually be OK in most cases where the caller of this function
924848b8605Smrg    * immediately uses the pointer.
925848b8605Smrg    */
926848b8605Smrg
927848b8605Smrg   u_box_2d(0, 0, res->width0, res->height0, &box);
928848b8605Smrg
929848b8605Smrg   *buffer = pipe->transfer_map(pipe, res, 0, PIPE_TRANSFER_READ, &box,
930848b8605Smrg                                &transfer);
931848b8605Smrg   if (!*buffer) {
932848b8605Smrg      return GL_FALSE;
933848b8605Smrg   }
934848b8605Smrg
935848b8605Smrg   *width = res->width0;
936848b8605Smrg   *height = res->height0;
937848b8605Smrg   *bytesPerValue = util_format_get_blocksize(res->format);
938848b8605Smrg
939848b8605Smrg   pipe->transfer_unmap(pipe, transfer);
940848b8605Smrg
941848b8605Smrg   return GL_TRUE;
942848b8605Smrg}
943848b8605Smrg
944848b8605Smrg
945848b8605Smrg/**
946848b8605Smrg * Return the color buffer associated with an OSMesa context.
947848b8605Smrg * Input:  c - the OSMesa context
948848b8605Smrg * Output:  width, height - size of buffer in pixels
949848b8605Smrg *          format - the pixel format (OSMESA_FORMAT)
950848b8605Smrg *          buffer - pointer to color buffer values
951848b8605Smrg * Return:  GL_TRUE or GL_FALSE to indicate success or failure.
952848b8605Smrg */
953848b8605SmrgGLAPI GLboolean GLAPIENTRY
954848b8605SmrgOSMesaGetColorBuffer(OSMesaContext osmesa, GLint *width,
955848b8605Smrg                      GLint *height, GLint *format, void **buffer)
956848b8605Smrg{
957848b8605Smrg   struct osmesa_buffer *osbuffer = osmesa->current_buffer;
958848b8605Smrg
959848b8605Smrg   if (osbuffer) {
960848b8605Smrg      *width = osbuffer->width;
961848b8605Smrg      *height = osbuffer->height;
962848b8605Smrg      *format = osmesa->format;
963848b8605Smrg      *buffer = osbuffer->map;
964848b8605Smrg      return GL_TRUE;
965848b8605Smrg   }
966848b8605Smrg   else {
967848b8605Smrg      *width = 0;
968848b8605Smrg      *height = 0;
969848b8605Smrg      *format = 0;
970848b8605Smrg      *buffer = 0;
971848b8605Smrg      return GL_FALSE;
972848b8605Smrg   }
973848b8605Smrg}
974848b8605Smrg
975848b8605Smrg
976848b8605Smrgstruct name_function
977848b8605Smrg{
978848b8605Smrg   const char *Name;
979848b8605Smrg   OSMESAproc Function;
980848b8605Smrg};
981848b8605Smrg
982848b8605Smrgstatic struct name_function functions[] = {
983848b8605Smrg   { "OSMesaCreateContext", (OSMESAproc) OSMesaCreateContext },
984848b8605Smrg   { "OSMesaCreateContextExt", (OSMESAproc) OSMesaCreateContextExt },
985b8e80941Smrg   { "OSMesaCreateContextAttribs", (OSMESAproc) OSMesaCreateContextAttribs },
986848b8605Smrg   { "OSMesaDestroyContext", (OSMESAproc) OSMesaDestroyContext },
987848b8605Smrg   { "OSMesaMakeCurrent", (OSMESAproc) OSMesaMakeCurrent },
988848b8605Smrg   { "OSMesaGetCurrentContext", (OSMESAproc) OSMesaGetCurrentContext },
989b8e80941Smrg   { "OSMesaPixelStore", (OSMESAproc) OSMesaPixelStore },
990848b8605Smrg   { "OSMesaGetIntegerv", (OSMESAproc) OSMesaGetIntegerv },
991848b8605Smrg   { "OSMesaGetDepthBuffer", (OSMESAproc) OSMesaGetDepthBuffer },
992848b8605Smrg   { "OSMesaGetColorBuffer", (OSMESAproc) OSMesaGetColorBuffer },
993848b8605Smrg   { "OSMesaGetProcAddress", (OSMESAproc) OSMesaGetProcAddress },
994848b8605Smrg   { "OSMesaColorClamp", (OSMESAproc) OSMesaColorClamp },
995848b8605Smrg   { "OSMesaPostprocess", (OSMESAproc) OSMesaPostprocess },
996848b8605Smrg   { NULL, NULL }
997848b8605Smrg};
998848b8605Smrg
999848b8605Smrg
1000848b8605SmrgGLAPI OSMESAproc GLAPIENTRY
1001848b8605SmrgOSMesaGetProcAddress(const char *funcName)
1002848b8605Smrg{
1003848b8605Smrg   int i;
1004848b8605Smrg   for (i = 0; functions[i].Name; i++) {
1005848b8605Smrg      if (strcmp(functions[i].Name, funcName) == 0)
1006848b8605Smrg         return functions[i].Function;
1007848b8605Smrg   }
1008848b8605Smrg   return _glapi_get_proc_address(funcName);
1009848b8605Smrg}
1010848b8605Smrg
1011848b8605Smrg
1012848b8605SmrgGLAPI void GLAPIENTRY
1013848b8605SmrgOSMesaColorClamp(GLboolean enable)
1014848b8605Smrg{
1015848b8605Smrg   extern void GLAPIENTRY _mesa_ClampColor(GLenum target, GLenum clamp);
1016848b8605Smrg
1017848b8605Smrg   _mesa_ClampColor(GL_CLAMP_FRAGMENT_COLOR_ARB,
1018848b8605Smrg                    enable ? GL_TRUE : GL_FIXED_ONLY_ARB);
1019848b8605Smrg}
1020848b8605Smrg
1021848b8605Smrg
1022848b8605SmrgGLAPI void GLAPIENTRY
1023848b8605SmrgOSMesaPostprocess(OSMesaContext osmesa, const char *filter,
1024848b8605Smrg                  unsigned enable_value)
1025848b8605Smrg{
1026848b8605Smrg   if (!osmesa->ever_used) {
1027848b8605Smrg      /* We can only enable/disable postprocess filters before a context
1028848b8605Smrg       * is made current for the first time.
1029848b8605Smrg       */
1030848b8605Smrg      unsigned i;
1031848b8605Smrg
1032848b8605Smrg      for (i = 0; i < PP_FILTERS; i++) {
1033848b8605Smrg         if (strcmp(pp_filters[i].name, filter) == 0) {
1034848b8605Smrg            osmesa->pp_enabled[i] = enable_value;
1035848b8605Smrg            return;
1036848b8605Smrg         }
1037848b8605Smrg      }
1038848b8605Smrg      debug_warning("OSMesaPostprocess(unknown filter)\n");
1039848b8605Smrg   }
1040848b8605Smrg   else {
1041848b8605Smrg      debug_warning("Calling OSMesaPostprocess() after OSMesaMakeCurrent()\n");
1042848b8605Smrg   }
1043848b8605Smrg}
1044