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