13464ebd5Sriastradh/*
23464ebd5Sriastradh * Mesa 3-D graphics library
33464ebd5Sriastradh *
43464ebd5Sriastradh * Copyright (C) 2010 LunarG Inc.
53464ebd5Sriastradh *
63464ebd5Sriastradh * Permission is hereby granted, free of charge, to any person obtaining a
73464ebd5Sriastradh * copy of this software and associated documentation files (the "Software"),
83464ebd5Sriastradh * to deal in the Software without restriction, including without limitation
93464ebd5Sriastradh * the rights to use, copy, modify, merge, publish, distribute, sublicense,
103464ebd5Sriastradh * and/or sell copies of the Software, and to permit persons to whom the
113464ebd5Sriastradh * Software is furnished to do so, subject to the following conditions:
123464ebd5Sriastradh *
133464ebd5Sriastradh * The above copyright notice and this permission notice shall be included
143464ebd5Sriastradh * in all copies or substantial portions of the Software.
153464ebd5Sriastradh *
163464ebd5Sriastradh * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
173464ebd5Sriastradh * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
183464ebd5Sriastradh * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
193464ebd5Sriastradh * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
203464ebd5Sriastradh * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
213464ebd5Sriastradh * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
223464ebd5Sriastradh * DEALINGS IN THE SOFTWARE.
233464ebd5Sriastradh *
243464ebd5Sriastradh * Authors:
253464ebd5Sriastradh *    Chia-I Wu <olv@lunarg.com>
263464ebd5Sriastradh */
273464ebd5Sriastradh
283464ebd5Sriastradh#include "main/mtypes.h"
29af69d88dSmrg#include "main/extensions.h"
303464ebd5Sriastradh#include "main/context.h"
3101e04c3fSmrg#include "main/debug_output.h"
3201e04c3fSmrg#include "main/glthread.h"
333464ebd5Sriastradh#include "main/texobj.h"
343464ebd5Sriastradh#include "main/teximage.h"
353464ebd5Sriastradh#include "main/texstate.h"
36af69d88dSmrg#include "main/errors.h"
373464ebd5Sriastradh#include "main/framebuffer.h"
383464ebd5Sriastradh#include "main/fbobject.h"
393464ebd5Sriastradh#include "main/renderbuffer.h"
403464ebd5Sriastradh#include "main/version.h"
4101e04c3fSmrg#include "util/hash_table.h"
423464ebd5Sriastradh#include "st_texture.h"
433464ebd5Sriastradh
443464ebd5Sriastradh#include "st_context.h"
4501e04c3fSmrg#include "st_debug.h"
46af69d88dSmrg#include "st_extensions.h"
473464ebd5Sriastradh#include "st_format.h"
4801e04c3fSmrg#include "st_cb_bitmap.h"
493464ebd5Sriastradh#include "st_cb_fbo.h"
503464ebd5Sriastradh#include "st_cb_flush.h"
513464ebd5Sriastradh#include "st_manager.h"
5201e04c3fSmrg#include "st_sampler_view.h"
533464ebd5Sriastradh
54af69d88dSmrg#include "state_tracker/st_gl_api.h"
55af69d88dSmrg
56af69d88dSmrg#include "pipe/p_context.h"
57af69d88dSmrg#include "pipe/p_screen.h"
587ec681f3Smrg#include "util/format/u_format.h"
5901e04c3fSmrg#include "util/u_helpers.h"
60af69d88dSmrg#include "util/u_pointer.h"
61af69d88dSmrg#include "util/u_inlines.h"
62af69d88dSmrg#include "util/u_atomic.h"
63af69d88dSmrg#include "util/u_surface.h"
6401e04c3fSmrg#include "util/list.h"
657ec681f3Smrg#include "util/u_memory.h"
66af69d88dSmrg
6701e04c3fSmrgstruct hash_table;
6801e04c3fSmrgstruct st_manager_private
693464ebd5Sriastradh{
7001e04c3fSmrg   struct hash_table *stfbi_ht; /* framebuffer iface objects hash table */
717ec681f3Smrg   simple_mtx_t st_mutex;
7201e04c3fSmrg};
7301e04c3fSmrg
743464ebd5Sriastradh
753464ebd5Sriastradh/**
763464ebd5Sriastradh * Map an attachment to a buffer index.
773464ebd5Sriastradh */
7801e04c3fSmrgstatic inline gl_buffer_index
793464ebd5Sriastradhattachment_to_buffer_index(enum st_attachment_type statt)
803464ebd5Sriastradh{
813464ebd5Sriastradh   gl_buffer_index index;
823464ebd5Sriastradh
833464ebd5Sriastradh   switch (statt) {
843464ebd5Sriastradh   case ST_ATTACHMENT_FRONT_LEFT:
853464ebd5Sriastradh      index = BUFFER_FRONT_LEFT;
863464ebd5Sriastradh      break;
873464ebd5Sriastradh   case ST_ATTACHMENT_BACK_LEFT:
883464ebd5Sriastradh      index = BUFFER_BACK_LEFT;
893464ebd5Sriastradh      break;
903464ebd5Sriastradh   case ST_ATTACHMENT_FRONT_RIGHT:
913464ebd5Sriastradh      index = BUFFER_FRONT_RIGHT;
923464ebd5Sriastradh      break;
933464ebd5Sriastradh   case ST_ATTACHMENT_BACK_RIGHT:
943464ebd5Sriastradh      index = BUFFER_BACK_RIGHT;
953464ebd5Sriastradh      break;
963464ebd5Sriastradh   case ST_ATTACHMENT_DEPTH_STENCIL:
973464ebd5Sriastradh      index = BUFFER_DEPTH;
983464ebd5Sriastradh      break;
993464ebd5Sriastradh   case ST_ATTACHMENT_ACCUM:
1003464ebd5Sriastradh      index = BUFFER_ACCUM;
1013464ebd5Sriastradh      break;
1023464ebd5Sriastradh   default:
1033464ebd5Sriastradh      index = BUFFER_COUNT;
1043464ebd5Sriastradh      break;
1053464ebd5Sriastradh   }
1063464ebd5Sriastradh
1073464ebd5Sriastradh   return index;
1083464ebd5Sriastradh}
1093464ebd5Sriastradh
11001e04c3fSmrg
1113464ebd5Sriastradh/**
1123464ebd5Sriastradh * Map a buffer index to an attachment.
1133464ebd5Sriastradh */
11401e04c3fSmrgstatic inline enum st_attachment_type
1153464ebd5Sriastradhbuffer_index_to_attachment(gl_buffer_index index)
1163464ebd5Sriastradh{
1173464ebd5Sriastradh   enum st_attachment_type statt;
1183464ebd5Sriastradh
1193464ebd5Sriastradh   switch (index) {
1203464ebd5Sriastradh   case BUFFER_FRONT_LEFT:
1213464ebd5Sriastradh      statt = ST_ATTACHMENT_FRONT_LEFT;
1223464ebd5Sriastradh      break;
1233464ebd5Sriastradh   case BUFFER_BACK_LEFT:
1243464ebd5Sriastradh      statt = ST_ATTACHMENT_BACK_LEFT;
1253464ebd5Sriastradh      break;
1263464ebd5Sriastradh   case BUFFER_FRONT_RIGHT:
1273464ebd5Sriastradh      statt = ST_ATTACHMENT_FRONT_RIGHT;
1283464ebd5Sriastradh      break;
1293464ebd5Sriastradh   case BUFFER_BACK_RIGHT:
1303464ebd5Sriastradh      statt = ST_ATTACHMENT_BACK_RIGHT;
1313464ebd5Sriastradh      break;
1323464ebd5Sriastradh   case BUFFER_DEPTH:
1333464ebd5Sriastradh      statt = ST_ATTACHMENT_DEPTH_STENCIL;
1343464ebd5Sriastradh      break;
1353464ebd5Sriastradh   case BUFFER_ACCUM:
1363464ebd5Sriastradh      statt = ST_ATTACHMENT_ACCUM;
1373464ebd5Sriastradh      break;
1383464ebd5Sriastradh   default:
1393464ebd5Sriastradh      statt = ST_ATTACHMENT_INVALID;
1403464ebd5Sriastradh      break;
1413464ebd5Sriastradh   }
1423464ebd5Sriastradh
1433464ebd5Sriastradh   return statt;
1443464ebd5Sriastradh}
1453464ebd5Sriastradh
14601e04c3fSmrg
147af69d88dSmrg/**
148af69d88dSmrg * Make sure a context picks up the latest cached state of the
149af69d88dSmrg * drawables it binds to.
150af69d88dSmrg */
151af69d88dSmrgstatic void
152af69d88dSmrgst_context_validate(struct st_context *st,
153af69d88dSmrg                    struct st_framebuffer *stdraw,
154af69d88dSmrg                    struct st_framebuffer *stread)
155af69d88dSmrg{
156af69d88dSmrg    if (stdraw && stdraw->stamp != st->draw_stamp) {
15701e04c3fSmrg       st->dirty |= ST_NEW_FRAMEBUFFER;
158af69d88dSmrg       _mesa_resize_framebuffer(st->ctx, &stdraw->Base,
159af69d88dSmrg                                stdraw->Base.Width,
160af69d88dSmrg                                stdraw->Base.Height);
161af69d88dSmrg       st->draw_stamp = stdraw->stamp;
162af69d88dSmrg    }
163af69d88dSmrg
164af69d88dSmrg    if (stread && stread->stamp != st->read_stamp) {
165af69d88dSmrg       if (stread != stdraw) {
16601e04c3fSmrg          st->dirty |= ST_NEW_FRAMEBUFFER;
167af69d88dSmrg          _mesa_resize_framebuffer(st->ctx, &stread->Base,
168af69d88dSmrg                                   stread->Base.Width,
169af69d88dSmrg                                   stread->Base.Height);
170af69d88dSmrg       }
171af69d88dSmrg       st->read_stamp = stread->stamp;
172af69d88dSmrg    }
173af69d88dSmrg}
174af69d88dSmrg
17501e04c3fSmrg
176b9abf16eSmayavoid
177b9abf16eSmayast_set_ws_renderbuffer_surface(struct st_renderbuffer *strb,
178b9abf16eSmaya                               struct pipe_surface *surf)
179b9abf16eSmaya{
180b9abf16eSmaya   pipe_surface_reference(&strb->surface_srgb, NULL);
181b9abf16eSmaya   pipe_surface_reference(&strb->surface_linear, NULL);
182b9abf16eSmaya
183b9abf16eSmaya   if (util_format_is_srgb(surf->format))
184b9abf16eSmaya      pipe_surface_reference(&strb->surface_srgb, surf);
185b9abf16eSmaya   else
186b9abf16eSmaya      pipe_surface_reference(&strb->surface_linear, surf);
187b9abf16eSmaya
188b9abf16eSmaya   strb->surface = surf; /* just assign, don't ref */
189b9abf16eSmaya   pipe_resource_reference(&strb->texture, surf->texture);
190b9abf16eSmaya
191b9abf16eSmaya   strb->Base.Width = surf->width;
192b9abf16eSmaya   strb->Base.Height = surf->height;
193b9abf16eSmaya}
194b9abf16eSmaya
195b9abf16eSmaya
1963464ebd5Sriastradh/**
1973464ebd5Sriastradh * Validate a framebuffer to make sure up-to-date pipe_textures are used.
198af69d88dSmrg * The context is only used for creating pipe surfaces and for calling
199af69d88dSmrg * _mesa_resize_framebuffer().
200af69d88dSmrg * (That should probably be rethought, since those surfaces become
201af69d88dSmrg * drawable state, not context state, and can be freed by another pipe
202af69d88dSmrg * context).
2033464ebd5Sriastradh */
2043464ebd5Sriastradhstatic void
205af69d88dSmrgst_framebuffer_validate(struct st_framebuffer *stfb,
206af69d88dSmrg                        struct st_context *st)
2073464ebd5Sriastradh{
2083464ebd5Sriastradh   struct pipe_resource *textures[ST_ATTACHMENT_COUNT];
2093464ebd5Sriastradh   uint width, height;
2103464ebd5Sriastradh   unsigned i;
2117ec681f3Smrg   bool changed = false;
212af69d88dSmrg   int32_t new_stamp;
2133464ebd5Sriastradh
214af69d88dSmrg   new_stamp = p_atomic_read(&stfb->iface->stamp);
215af69d88dSmrg   if (stfb->iface_stamp == new_stamp)
2163464ebd5Sriastradh      return;
2173464ebd5Sriastradh
21801e04c3fSmrg   memset(textures, 0, stfb->num_statts * sizeof(textures[0]));
21901e04c3fSmrg
220af69d88dSmrg   /* validate the fb */
221af69d88dSmrg   do {
222af69d88dSmrg      if (!stfb->iface->validate(&st->iface, stfb->iface, stfb->statts,
22301e04c3fSmrg                                 stfb->num_statts, textures))
22401e04c3fSmrg         return;
225af69d88dSmrg
226af69d88dSmrg      stfb->iface_stamp = new_stamp;
227af69d88dSmrg      new_stamp = p_atomic_read(&stfb->iface->stamp);
228af69d88dSmrg   } while(stfb->iface_stamp != new_stamp);
229af69d88dSmrg
2303464ebd5Sriastradh   width = stfb->Base.Width;
2313464ebd5Sriastradh   height = stfb->Base.Height;
2323464ebd5Sriastradh
2333464ebd5Sriastradh   for (i = 0; i < stfb->num_statts; i++) {
2343464ebd5Sriastradh      struct st_renderbuffer *strb;
2353464ebd5Sriastradh      struct pipe_surface *ps, surf_tmpl;
2363464ebd5Sriastradh      gl_buffer_index idx;
2373464ebd5Sriastradh
2383464ebd5Sriastradh      if (!textures[i])
2393464ebd5Sriastradh         continue;
2403464ebd5Sriastradh
2413464ebd5Sriastradh      idx = attachment_to_buffer_index(stfb->statts[i]);
2423464ebd5Sriastradh      if (idx >= BUFFER_COUNT) {
2433464ebd5Sriastradh         pipe_resource_reference(&textures[i], NULL);
2443464ebd5Sriastradh         continue;
2453464ebd5Sriastradh      }
2463464ebd5Sriastradh
2473464ebd5Sriastradh      strb = st_renderbuffer(stfb->Base.Attachment[idx].Renderbuffer);
2483464ebd5Sriastradh      assert(strb);
2493464ebd5Sriastradh      if (strb->texture == textures[i]) {
2503464ebd5Sriastradh         pipe_resource_reference(&textures[i], NULL);
2513464ebd5Sriastradh         continue;
2523464ebd5Sriastradh      }
2533464ebd5Sriastradh
254af69d88dSmrg      u_surface_default_template(&surf_tmpl, textures[i]);
255af69d88dSmrg      ps = st->pipe->create_surface(st->pipe, textures[i], &surf_tmpl);
2563464ebd5Sriastradh      if (ps) {
257b9abf16eSmaya         st_set_ws_renderbuffer_surface(strb, ps);
2583464ebd5Sriastradh         pipe_surface_reference(&ps, NULL);
2593464ebd5Sriastradh
2607ec681f3Smrg         changed = true;
2613464ebd5Sriastradh
2623464ebd5Sriastradh         width = strb->Base.Width;
2633464ebd5Sriastradh         height = strb->Base.Height;
2643464ebd5Sriastradh      }
2653464ebd5Sriastradh
2663464ebd5Sriastradh      pipe_resource_reference(&textures[i], NULL);
2673464ebd5Sriastradh   }
2683464ebd5Sriastradh
2693464ebd5Sriastradh   if (changed) {
270af69d88dSmrg      ++stfb->stamp;
2713464ebd5Sriastradh      _mesa_resize_framebuffer(st->ctx, &stfb->Base, width, height);
2723464ebd5Sriastradh   }
2733464ebd5Sriastradh}
2743464ebd5Sriastradh
27501e04c3fSmrg
2763464ebd5Sriastradh/**
2773464ebd5Sriastradh * Update the attachments to validate by looping the existing renderbuffers.
2783464ebd5Sriastradh */
2793464ebd5Sriastradhstatic void
2803464ebd5Sriastradhst_framebuffer_update_attachments(struct st_framebuffer *stfb)
2813464ebd5Sriastradh{
2823464ebd5Sriastradh   gl_buffer_index idx;
2833464ebd5Sriastradh
2843464ebd5Sriastradh   stfb->num_statts = 0;
2857ec681f3Smrg
2867ec681f3Smrg   for (enum st_attachment_type i = 0; i < ST_ATTACHMENT_COUNT; i++)
2877ec681f3Smrg      stfb->statts[i] = ST_ATTACHMENT_INVALID;
2887ec681f3Smrg
2893464ebd5Sriastradh   for (idx = 0; idx < BUFFER_COUNT; idx++) {
2903464ebd5Sriastradh      struct st_renderbuffer *strb;
2913464ebd5Sriastradh      enum st_attachment_type statt;
2923464ebd5Sriastradh
2933464ebd5Sriastradh      strb = st_renderbuffer(stfb->Base.Attachment[idx].Renderbuffer);
2943464ebd5Sriastradh      if (!strb || strb->software)
2953464ebd5Sriastradh         continue;
2963464ebd5Sriastradh
2973464ebd5Sriastradh      statt = buffer_index_to_attachment(idx);
2983464ebd5Sriastradh      if (statt != ST_ATTACHMENT_INVALID &&
2993464ebd5Sriastradh          st_visual_have_buffers(stfb->iface->visual, 1 << statt))
3003464ebd5Sriastradh         stfb->statts[stfb->num_statts++] = statt;
3013464ebd5Sriastradh   }
302af69d88dSmrg   stfb->stamp++;
3033464ebd5Sriastradh}
3043464ebd5Sriastradh
30501e04c3fSmrg
3063464ebd5Sriastradh/**
30701e04c3fSmrg * Add a renderbuffer to the framebuffer.  The framebuffer is one that
30801e04c3fSmrg * corresponds to a window and is not a user-created FBO.
3093464ebd5Sriastradh */
3107ec681f3Smrgstatic bool
3113464ebd5Sriastradhst_framebuffer_add_renderbuffer(struct st_framebuffer *stfb,
312b9abf16eSmaya                                gl_buffer_index idx, bool prefer_srgb)
3133464ebd5Sriastradh{
3143464ebd5Sriastradh   struct gl_renderbuffer *rb;
3153464ebd5Sriastradh   enum pipe_format format;
3167ec681f3Smrg   bool sw;
3173464ebd5Sriastradh
31801e04c3fSmrg   assert(_mesa_is_winsys_fbo(&stfb->Base));
3193464ebd5Sriastradh
3203464ebd5Sriastradh   /* do not distinguish depth/stencil buffers */
3213464ebd5Sriastradh   if (idx == BUFFER_STENCIL)
3223464ebd5Sriastradh      idx = BUFFER_DEPTH;
3233464ebd5Sriastradh
3243464ebd5Sriastradh   switch (idx) {
3253464ebd5Sriastradh   case BUFFER_DEPTH:
3263464ebd5Sriastradh      format = stfb->iface->visual->depth_stencil_format;
3277ec681f3Smrg      sw = false;
3283464ebd5Sriastradh      break;
3293464ebd5Sriastradh   case BUFFER_ACCUM:
3303464ebd5Sriastradh      format = stfb->iface->visual->accum_format;
3317ec681f3Smrg      sw = true;
3323464ebd5Sriastradh      break;
3333464ebd5Sriastradh   default:
3343464ebd5Sriastradh      format = stfb->iface->visual->color_format;
335b9abf16eSmaya      if (prefer_srgb)
336af69d88dSmrg         format = util_format_srgb(format);
3377ec681f3Smrg      sw = false;
3383464ebd5Sriastradh      break;
3393464ebd5Sriastradh   }
3403464ebd5Sriastradh
3413464ebd5Sriastradh   if (format == PIPE_FORMAT_NONE)
3427ec681f3Smrg      return false;
3433464ebd5Sriastradh
344af69d88dSmrg   rb = st_new_renderbuffer_fb(format, stfb->iface->visual->samples, sw);
3453464ebd5Sriastradh   if (!rb)
3467ec681f3Smrg      return false;
3473464ebd5Sriastradh
3483464ebd5Sriastradh   if (idx != BUFFER_DEPTH) {
34901e04c3fSmrg      _mesa_attach_and_own_rb(&stfb->Base, idx, rb);
3507ec681f3Smrg      return true;
3513464ebd5Sriastradh   }
35201e04c3fSmrg
35301e04c3fSmrg   bool rb_ownership_taken = false;
35401e04c3fSmrg   if (util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_ZS, 0)) {
35501e04c3fSmrg      _mesa_attach_and_own_rb(&stfb->Base, BUFFER_DEPTH, rb);
35601e04c3fSmrg      rb_ownership_taken = true;
35701e04c3fSmrg   }
35801e04c3fSmrg
35901e04c3fSmrg   if (util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_ZS, 1)) {
36001e04c3fSmrg      if (rb_ownership_taken)
36101e04c3fSmrg         _mesa_attach_and_reference_rb(&stfb->Base, BUFFER_STENCIL, rb);
36201e04c3fSmrg      else
36301e04c3fSmrg         _mesa_attach_and_own_rb(&stfb->Base, BUFFER_STENCIL, rb);
3643464ebd5Sriastradh   }
3653464ebd5Sriastradh
3667ec681f3Smrg   return true;
3673464ebd5Sriastradh}
3683464ebd5Sriastradh
36901e04c3fSmrg
3703464ebd5Sriastradh/**
3713464ebd5Sriastradh * Intialize a struct gl_config from a visual.
3723464ebd5Sriastradh */
3733464ebd5Sriastradhstatic void
3743464ebd5Sriastradhst_visual_to_context_mode(const struct st_visual *visual,
3753464ebd5Sriastradh                          struct gl_config *mode)
3763464ebd5Sriastradh{
3773464ebd5Sriastradh   memset(mode, 0, sizeof(*mode));
3783464ebd5Sriastradh
3793464ebd5Sriastradh   if (st_visual_have_buffers(visual, ST_ATTACHMENT_BACK_LEFT_MASK))
3803464ebd5Sriastradh      mode->doubleBufferMode = GL_TRUE;
38101e04c3fSmrg
3823464ebd5Sriastradh   if (st_visual_have_buffers(visual,
3833464ebd5Sriastradh            ST_ATTACHMENT_FRONT_RIGHT_MASK | ST_ATTACHMENT_BACK_RIGHT_MASK))
3843464ebd5Sriastradh      mode->stereoMode = GL_TRUE;
3853464ebd5Sriastradh
3863464ebd5Sriastradh   if (visual->color_format != PIPE_FORMAT_NONE) {
3873464ebd5Sriastradh      mode->redBits =
3883464ebd5Sriastradh         util_format_get_component_bits(visual->color_format,
3893464ebd5Sriastradh               UTIL_FORMAT_COLORSPACE_RGB, 0);
3903464ebd5Sriastradh      mode->greenBits =
3913464ebd5Sriastradh         util_format_get_component_bits(visual->color_format,
3923464ebd5Sriastradh               UTIL_FORMAT_COLORSPACE_RGB, 1);
3933464ebd5Sriastradh      mode->blueBits =
3943464ebd5Sriastradh         util_format_get_component_bits(visual->color_format,
3953464ebd5Sriastradh               UTIL_FORMAT_COLORSPACE_RGB, 2);
3963464ebd5Sriastradh      mode->alphaBits =
3973464ebd5Sriastradh         util_format_get_component_bits(visual->color_format,
3983464ebd5Sriastradh               UTIL_FORMAT_COLORSPACE_RGB, 3);
3993464ebd5Sriastradh
4003464ebd5Sriastradh      mode->rgbBits = mode->redBits +
4013464ebd5Sriastradh         mode->greenBits + mode->blueBits + mode->alphaBits;
40201e04c3fSmrg      mode->sRGBCapable = util_format_is_srgb(visual->color_format);
4033464ebd5Sriastradh   }
4043464ebd5Sriastradh
4053464ebd5Sriastradh   if (visual->depth_stencil_format != PIPE_FORMAT_NONE) {
4063464ebd5Sriastradh      mode->depthBits =
4073464ebd5Sriastradh         util_format_get_component_bits(visual->depth_stencil_format,
4083464ebd5Sriastradh               UTIL_FORMAT_COLORSPACE_ZS, 0);
4093464ebd5Sriastradh      mode->stencilBits =
4103464ebd5Sriastradh         util_format_get_component_bits(visual->depth_stencil_format,
4113464ebd5Sriastradh               UTIL_FORMAT_COLORSPACE_ZS, 1);
4123464ebd5Sriastradh   }
4133464ebd5Sriastradh
4143464ebd5Sriastradh   if (visual->accum_format != PIPE_FORMAT_NONE) {
4153464ebd5Sriastradh      mode->accumRedBits =
4163464ebd5Sriastradh         util_format_get_component_bits(visual->accum_format,
4173464ebd5Sriastradh               UTIL_FORMAT_COLORSPACE_RGB, 0);
4183464ebd5Sriastradh      mode->accumGreenBits =
4193464ebd5Sriastradh         util_format_get_component_bits(visual->accum_format,
4203464ebd5Sriastradh               UTIL_FORMAT_COLORSPACE_RGB, 1);
4213464ebd5Sriastradh      mode->accumBlueBits =
4223464ebd5Sriastradh         util_format_get_component_bits(visual->accum_format,
4233464ebd5Sriastradh               UTIL_FORMAT_COLORSPACE_RGB, 2);
4243464ebd5Sriastradh      mode->accumAlphaBits =
4253464ebd5Sriastradh         util_format_get_component_bits(visual->accum_format,
4263464ebd5Sriastradh               UTIL_FORMAT_COLORSPACE_RGB, 3);
4273464ebd5Sriastradh   }
4283464ebd5Sriastradh
429af69d88dSmrg   if (visual->samples > 1) {
4303464ebd5Sriastradh      mode->samples = visual->samples;
4313464ebd5Sriastradh   }
4323464ebd5Sriastradh}
4333464ebd5Sriastradh
43401e04c3fSmrg
4353464ebd5Sriastradh/**
4363464ebd5Sriastradh * Create a framebuffer from a manager interface.
4373464ebd5Sriastradh */
4383464ebd5Sriastradhstatic struct st_framebuffer *
439af69d88dSmrgst_framebuffer_create(struct st_context *st,
440af69d88dSmrg                      struct st_framebuffer_iface *stfbi)
4413464ebd5Sriastradh{
4423464ebd5Sriastradh   struct st_framebuffer *stfb;
4433464ebd5Sriastradh   struct gl_config mode;
4443464ebd5Sriastradh   gl_buffer_index idx;
445b9abf16eSmaya   bool prefer_srgb = false;
4463464ebd5Sriastradh
4473464ebd5Sriastradh   if (!stfbi)
4483464ebd5Sriastradh      return NULL;
4493464ebd5Sriastradh
4503464ebd5Sriastradh   stfb = CALLOC_STRUCT(st_framebuffer);
4513464ebd5Sriastradh   if (!stfb)
4523464ebd5Sriastradh      return NULL;
4533464ebd5Sriastradh
4543464ebd5Sriastradh   st_visual_to_context_mode(stfbi->visual, &mode);
4553464ebd5Sriastradh
456af69d88dSmrg   /*
457af69d88dSmrg    * For desktop GL, sRGB framebuffer write is controlled by both the
458af69d88dSmrg    * capability of the framebuffer and GL_FRAMEBUFFER_SRGB.  We should
459af69d88dSmrg    * advertise the capability when the pipe driver (and core Mesa) supports
460af69d88dSmrg    * it so that applications can enable sRGB write when they want to.
461af69d88dSmrg    *
462af69d88dSmrg    * This is not to be confused with GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB.  When
463af69d88dSmrg    * the attribute is GLX_TRUE, it tells the st manager to pick a color
464af69d88dSmrg    * format such that util_format_srgb(visual->color_format) can be supported
465af69d88dSmrg    * by the pipe driver.  We still need to advertise the capability here.
466af69d88dSmrg    *
467b9abf16eSmaya    * For GLES, however, sRGB framebuffer write is initially only controlled
468b9abf16eSmaya    * by the capability of the framebuffer, with GL_EXT_sRGB_write_control
469b9abf16eSmaya    * control is given back to the applications, but GL_FRAMEBUFFER_SRGB is
470b9abf16eSmaya    * still enabled by default since this is the behaviour when
471b9abf16eSmaya    * EXT_sRGB_write_control is not available. Since GL_EXT_sRGB_write_control
472b9abf16eSmaya    * brings GLES on par with desktop GLs EXT_framebuffer_sRGB, in mesa this
473b9abf16eSmaya    * is also expressed by using the same extension flag
474af69d88dSmrg    */
475b9abf16eSmaya   if (_mesa_has_EXT_framebuffer_sRGB(st->ctx)) {
4767ec681f3Smrg      struct pipe_screen *screen = st->screen;
477af69d88dSmrg      const enum pipe_format srgb_format =
478af69d88dSmrg         util_format_srgb(stfbi->visual->color_format);
479af69d88dSmrg
480af69d88dSmrg      if (srgb_format != PIPE_FORMAT_NONE &&
481af69d88dSmrg          st_pipe_format_to_mesa_format(srgb_format) != MESA_FORMAT_NONE &&
482af69d88dSmrg          screen->is_format_supported(screen, srgb_format,
483af69d88dSmrg                                      PIPE_TEXTURE_2D, stfbi->visual->samples,
48401e04c3fSmrg                                      stfbi->visual->samples,
48501e04c3fSmrg                                      (PIPE_BIND_DISPLAY_TARGET |
486b9abf16eSmaya                                       PIPE_BIND_RENDER_TARGET))) {
487af69d88dSmrg         mode.sRGBCapable = GL_TRUE;
488b9abf16eSmaya         /* Since GL_FRAMEBUFFER_SRGB is enabled by default on GLES we must not
489b9abf16eSmaya          * create renderbuffers with an sRGB format derived from the
490b9abf16eSmaya          * visual->color_format, but we still want sRGB for desktop GL.
491b9abf16eSmaya          */
492b9abf16eSmaya         prefer_srgb = _mesa_is_desktop_gl(st->ctx);
493b9abf16eSmaya      }
494af69d88dSmrg   }
495af69d88dSmrg
496af69d88dSmrg   _mesa_initialize_window_framebuffer(&stfb->Base, &mode);
4973464ebd5Sriastradh
4983464ebd5Sriastradh   stfb->iface = stfbi;
49901e04c3fSmrg   stfb->iface_ID = stfbi->ID;
500af69d88dSmrg   stfb->iface_stamp = p_atomic_read(&stfbi->stamp) - 1;
5013464ebd5Sriastradh
5023464ebd5Sriastradh   /* add the color buffer */
5033464ebd5Sriastradh   idx = stfb->Base._ColorDrawBufferIndexes[0];
504b9abf16eSmaya   if (!st_framebuffer_add_renderbuffer(stfb, idx, prefer_srgb)) {
505af69d88dSmrg      free(stfb);
5063464ebd5Sriastradh      return NULL;
5073464ebd5Sriastradh   }
5083464ebd5Sriastradh
509b9abf16eSmaya   st_framebuffer_add_renderbuffer(stfb, BUFFER_DEPTH, false);
510b9abf16eSmaya   st_framebuffer_add_renderbuffer(stfb, BUFFER_ACCUM, false);
5113464ebd5Sriastradh
512af69d88dSmrg   stfb->stamp = 0;
5133464ebd5Sriastradh   st_framebuffer_update_attachments(stfb);
5143464ebd5Sriastradh
5153464ebd5Sriastradh   return stfb;
5163464ebd5Sriastradh}
5173464ebd5Sriastradh
51801e04c3fSmrg
5193464ebd5Sriastradh/**
5203464ebd5Sriastradh * Reference a framebuffer.
5213464ebd5Sriastradh */
52201e04c3fSmrgvoid
5233464ebd5Sriastradhst_framebuffer_reference(struct st_framebuffer **ptr,
5243464ebd5Sriastradh                         struct st_framebuffer *stfb)
5253464ebd5Sriastradh{
5267ec681f3Smrg   struct gl_framebuffer *fb = stfb ? &stfb->Base : NULL;
5273464ebd5Sriastradh   _mesa_reference_framebuffer((struct gl_framebuffer **) ptr, fb);
5283464ebd5Sriastradh}
5293464ebd5Sriastradh
53001e04c3fSmrg
53101e04c3fSmrgstatic uint32_t
53201e04c3fSmrgst_framebuffer_iface_hash(const void *key)
53301e04c3fSmrg{
53401e04c3fSmrg   return (uintptr_t)key;
53501e04c3fSmrg}
53601e04c3fSmrg
53701e04c3fSmrg
53801e04c3fSmrgstatic bool
53901e04c3fSmrgst_framebuffer_iface_equal(const void *a, const void *b)
54001e04c3fSmrg{
54101e04c3fSmrg   return (struct st_framebuffer_iface *)a == (struct st_framebuffer_iface *)b;
54201e04c3fSmrg}
54301e04c3fSmrg
54401e04c3fSmrg
5457ec681f3Smrgstatic bool
54601e04c3fSmrgst_framebuffer_iface_lookup(struct st_manager *smapi,
54701e04c3fSmrg                            const struct st_framebuffer_iface *stfbi)
54801e04c3fSmrg{
54901e04c3fSmrg   struct st_manager_private *smPriv =
55001e04c3fSmrg      (struct st_manager_private *)smapi->st_manager_private;
55101e04c3fSmrg   struct hash_entry *entry;
55201e04c3fSmrg
55301e04c3fSmrg   assert(smPriv);
55401e04c3fSmrg   assert(smPriv->stfbi_ht);
55501e04c3fSmrg
5567ec681f3Smrg   simple_mtx_lock(&smPriv->st_mutex);
55701e04c3fSmrg   entry = _mesa_hash_table_search(smPriv->stfbi_ht, stfbi);
5587ec681f3Smrg   simple_mtx_unlock(&smPriv->st_mutex);
55901e04c3fSmrg
56001e04c3fSmrg   return entry != NULL;
56101e04c3fSmrg}
56201e04c3fSmrg
56301e04c3fSmrg
5647ec681f3Smrgstatic bool
56501e04c3fSmrgst_framebuffer_iface_insert(struct st_manager *smapi,
56601e04c3fSmrg                            struct st_framebuffer_iface *stfbi)
56701e04c3fSmrg{
56801e04c3fSmrg   struct st_manager_private *smPriv =
56901e04c3fSmrg      (struct st_manager_private *)smapi->st_manager_private;
57001e04c3fSmrg   struct hash_entry *entry;
57101e04c3fSmrg
57201e04c3fSmrg   assert(smPriv);
57301e04c3fSmrg   assert(smPriv->stfbi_ht);
57401e04c3fSmrg
5757ec681f3Smrg   simple_mtx_lock(&smPriv->st_mutex);
57601e04c3fSmrg   entry = _mesa_hash_table_insert(smPriv->stfbi_ht, stfbi, stfbi);
5777ec681f3Smrg   simple_mtx_unlock(&smPriv->st_mutex);
57801e04c3fSmrg
57901e04c3fSmrg   return entry != NULL;
58001e04c3fSmrg}
58101e04c3fSmrg
58201e04c3fSmrg
58301e04c3fSmrgstatic void
58401e04c3fSmrgst_framebuffer_iface_remove(struct st_manager *smapi,
58501e04c3fSmrg                            struct st_framebuffer_iface *stfbi)
58601e04c3fSmrg{
58701e04c3fSmrg   struct st_manager_private *smPriv =
58801e04c3fSmrg      (struct st_manager_private *)smapi->st_manager_private;
58901e04c3fSmrg   struct hash_entry *entry;
59001e04c3fSmrg
59101e04c3fSmrg   if (!smPriv || !smPriv->stfbi_ht)
59201e04c3fSmrg      return;
59301e04c3fSmrg
5947ec681f3Smrg   simple_mtx_lock(&smPriv->st_mutex);
59501e04c3fSmrg   entry = _mesa_hash_table_search(smPriv->stfbi_ht, stfbi);
59601e04c3fSmrg   if (!entry)
59701e04c3fSmrg      goto unlock;
59801e04c3fSmrg
59901e04c3fSmrg   _mesa_hash_table_remove(smPriv->stfbi_ht, entry);
60001e04c3fSmrg
60101e04c3fSmrgunlock:
6027ec681f3Smrg   simple_mtx_unlock(&smPriv->st_mutex);
60301e04c3fSmrg}
60401e04c3fSmrg
60501e04c3fSmrg
60601e04c3fSmrg/**
60701e04c3fSmrg * The framebuffer interface object is no longer valid.
60801e04c3fSmrg * Remove the object from the framebuffer interface hash table.
60901e04c3fSmrg */
61001e04c3fSmrgstatic void
61101e04c3fSmrgst_api_destroy_drawable(struct st_api *stapi,
61201e04c3fSmrg                        struct st_framebuffer_iface *stfbi)
61301e04c3fSmrg{
61401e04c3fSmrg   if (!stfbi)
61501e04c3fSmrg      return;
61601e04c3fSmrg
61701e04c3fSmrg   st_framebuffer_iface_remove(stfbi->state_manager, stfbi);
61801e04c3fSmrg}
61901e04c3fSmrg
62001e04c3fSmrg
62101e04c3fSmrg/**
62201e04c3fSmrg * Purge the winsys buffers list to remove any references to
62301e04c3fSmrg * non-existing framebuffer interface objects.
62401e04c3fSmrg */
62501e04c3fSmrgstatic void
62601e04c3fSmrgst_framebuffers_purge(struct st_context *st)
62701e04c3fSmrg{
62801e04c3fSmrg   struct st_context_iface *st_iface = &st->iface;
62901e04c3fSmrg   struct st_manager *smapi = st_iface->state_manager;
63001e04c3fSmrg   struct st_framebuffer *stfb, *next;
63101e04c3fSmrg
63201e04c3fSmrg   assert(smapi);
63301e04c3fSmrg
63401e04c3fSmrg   LIST_FOR_EACH_ENTRY_SAFE_REV(stfb, next, &st->winsys_buffers, head) {
63501e04c3fSmrg      struct st_framebuffer_iface *stfbi = stfb->iface;
63601e04c3fSmrg
63701e04c3fSmrg      assert(stfbi);
63801e04c3fSmrg
63901e04c3fSmrg      /**
64001e04c3fSmrg       * If the corresponding framebuffer interface object no longer exists,
64101e04c3fSmrg       * remove the framebuffer object from the context's winsys buffers list,
64201e04c3fSmrg       * and unreference the framebuffer object, so its resources can be
64301e04c3fSmrg       * deleted.
64401e04c3fSmrg       */
64501e04c3fSmrg      if (!st_framebuffer_iface_lookup(smapi, stfbi)) {
6467ec681f3Smrg         list_del(&stfb->head);
64701e04c3fSmrg         st_framebuffer_reference(&stfb, NULL);
64801e04c3fSmrg      }
64901e04c3fSmrg   }
65001e04c3fSmrg}
65101e04c3fSmrg
65201e04c3fSmrg
6533464ebd5Sriastradhstatic void
654af69d88dSmrgst_context_flush(struct st_context_iface *stctxi, unsigned flags,
6557ec681f3Smrg                 struct pipe_fence_handle **fence,
6567ec681f3Smrg                 void (*before_flush_cb) (void*),
6577ec681f3Smrg                 void* args)
6583464ebd5Sriastradh{
6593464ebd5Sriastradh   struct st_context *st = (struct st_context *) stctxi;
660af69d88dSmrg   unsigned pipe_flags = 0;
6613464ebd5Sriastradh
66201e04c3fSmrg   if (flags & ST_FLUSH_END_OF_FRAME)
663af69d88dSmrg      pipe_flags |= PIPE_FLUSH_END_OF_FRAME;
66401e04c3fSmrg   if (flags & ST_FLUSH_FENCE_FD)
66501e04c3fSmrg      pipe_flags |= PIPE_FLUSH_FENCE_FD;
6663464ebd5Sriastradh
6677ec681f3Smrg   /* We can do these in any order because FLUSH_VERTICES will also flush
6687ec681f3Smrg    * the bitmap cache if there are any unflushed vertices.
6697ec681f3Smrg    */
6707ec681f3Smrg   st_flush_bitmap_cache(st);
6717ec681f3Smrg   FLUSH_VERTICES(st->ctx, 0, 0);
6727ec681f3Smrg
6737ec681f3Smrg   /* Notify the caller that we're ready to flush */
6747ec681f3Smrg   if (before_flush_cb)
6757ec681f3Smrg      before_flush_cb(args);
676af69d88dSmrg   st_flush(st, fence, pipe_flags);
67701e04c3fSmrg
67801e04c3fSmrg   if ((flags & ST_FLUSH_WAIT) && fence && *fence) {
6797ec681f3Smrg      st->screen->fence_finish(st->screen, NULL, *fence,
68001e04c3fSmrg                                     PIPE_TIMEOUT_INFINITE);
6817ec681f3Smrg      st->screen->fence_reference(st->screen, fence, NULL);
68201e04c3fSmrg   }
68301e04c3fSmrg
6843464ebd5Sriastradh   if (flags & ST_FLUSH_FRONT)
6853464ebd5Sriastradh      st_manager_flush_frontbuffer(st);
68601e04c3fSmrg
68701e04c3fSmrg   /* DRI3 changes the framebuffer after SwapBuffers, but we need to invoke
68801e04c3fSmrg    * st_manager_validate_framebuffers to notice that.
68901e04c3fSmrg    *
69001e04c3fSmrg    * Set gfx_shaders_may_be_dirty to invoke st_validate_state in the next
69101e04c3fSmrg    * draw call, which will invoke st_manager_validate_framebuffers, but it
69201e04c3fSmrg    * won't dirty states if there is no change.
69301e04c3fSmrg    */
69401e04c3fSmrg   if (flags & ST_FLUSH_END_OF_FRAME)
69501e04c3fSmrg      st->gfx_shaders_may_be_dirty = true;
6963464ebd5Sriastradh}
6973464ebd5Sriastradh
6987ec681f3Smrgstatic bool
6993464ebd5Sriastradhst_context_teximage(struct st_context_iface *stctxi,
700af69d88dSmrg                    enum st_texture_type tex_type,
701af69d88dSmrg                    int level, enum pipe_format pipe_format,
7027ec681f3Smrg                    struct pipe_resource *tex, bool mipmap)
7033464ebd5Sriastradh{
7043464ebd5Sriastradh   struct st_context *st = (struct st_context *) stctxi;
7053464ebd5Sriastradh   struct gl_context *ctx = st->ctx;
7063464ebd5Sriastradh   struct gl_texture_object *texObj;
7073464ebd5Sriastradh   struct gl_texture_image *texImage;
7083464ebd5Sriastradh   struct st_texture_object *stObj;
7093464ebd5Sriastradh   struct st_texture_image *stImage;
7103464ebd5Sriastradh   GLenum internalFormat;
7113464ebd5Sriastradh   GLuint width, height, depth;
712af69d88dSmrg   GLenum target;
7133464ebd5Sriastradh
714af69d88dSmrg   switch (tex_type) {
7153464ebd5Sriastradh   case ST_TEXTURE_1D:
7163464ebd5Sriastradh      target = GL_TEXTURE_1D;
7173464ebd5Sriastradh      break;
7183464ebd5Sriastradh   case ST_TEXTURE_2D:
7193464ebd5Sriastradh      target = GL_TEXTURE_2D;
7203464ebd5Sriastradh      break;
7213464ebd5Sriastradh   case ST_TEXTURE_3D:
7223464ebd5Sriastradh      target = GL_TEXTURE_3D;
7233464ebd5Sriastradh      break;
7243464ebd5Sriastradh   case ST_TEXTURE_RECT:
7253464ebd5Sriastradh      target = GL_TEXTURE_RECTANGLE_ARB;
7263464ebd5Sriastradh      break;
7273464ebd5Sriastradh   default:
7283464ebd5Sriastradh      return FALSE;
7293464ebd5Sriastradh   }
7303464ebd5Sriastradh
731af69d88dSmrg   texObj = _mesa_get_current_tex_object(ctx, target);
732af69d88dSmrg
7333464ebd5Sriastradh   _mesa_lock_texture(ctx, texObj);
7343464ebd5Sriastradh
7353464ebd5Sriastradh   stObj = st_texture_object(texObj);
7363464ebd5Sriastradh   /* switch to surface based */
7373464ebd5Sriastradh   if (!stObj->surface_based) {
73801e04c3fSmrg      _mesa_clear_texture_object(ctx, texObj, NULL);
7393464ebd5Sriastradh      stObj->surface_based = GL_TRUE;
7403464ebd5Sriastradh   }
7413464ebd5Sriastradh
7423464ebd5Sriastradh   texImage = _mesa_get_tex_image(ctx, texObj, target, level);
7433464ebd5Sriastradh   stImage = st_texture_image(texImage);
7443464ebd5Sriastradh   if (tex) {
745af69d88dSmrg      mesa_format texFormat = st_pipe_format_to_mesa_format(pipe_format);
746af69d88dSmrg
747af69d88dSmrg      if (util_format_has_alpha(tex->format))
7483464ebd5Sriastradh         internalFormat = GL_RGBA;
7493464ebd5Sriastradh      else
7503464ebd5Sriastradh         internalFormat = GL_RGB;
7513464ebd5Sriastradh
752af69d88dSmrg      _mesa_init_teximage_fields(ctx, texImage,
7533464ebd5Sriastradh                                 tex->width0, tex->height0, 1, 0,
7543464ebd5Sriastradh                                 internalFormat, texFormat);
7553464ebd5Sriastradh
7563464ebd5Sriastradh      width = tex->width0;
7573464ebd5Sriastradh      height = tex->height0;
7583464ebd5Sriastradh      depth = tex->depth0;
7593464ebd5Sriastradh
7603464ebd5Sriastradh      /* grow the image size until we hit level = 0 */
7613464ebd5Sriastradh      while (level > 0) {
7623464ebd5Sriastradh         if (width != 1)
7633464ebd5Sriastradh            width <<= 1;
7643464ebd5Sriastradh         if (height != 1)
7653464ebd5Sriastradh            height <<= 1;
7663464ebd5Sriastradh         if (depth != 1)
7673464ebd5Sriastradh            depth <<= 1;
7683464ebd5Sriastradh         level--;
7693464ebd5Sriastradh      }
7703464ebd5Sriastradh   }
7713464ebd5Sriastradh   else {
7723464ebd5Sriastradh      _mesa_clear_texture_image(ctx, texImage);
7733464ebd5Sriastradh      width = height = depth = 0;
7743464ebd5Sriastradh   }
7753464ebd5Sriastradh
77601e04c3fSmrg   pipe_resource_reference(&stObj->pt, tex);
77701e04c3fSmrg   st_texture_release_all_sampler_views(st, stObj);
7783464ebd5Sriastradh   pipe_resource_reference(&stImage->pt, tex);
779af69d88dSmrg   stObj->surface_format = pipe_format;
7803464ebd5Sriastradh
78101e04c3fSmrg   stObj->needs_validation = true;
78201e04c3fSmrg
783af69d88dSmrg   _mesa_dirty_texobj(ctx, texObj);
7843464ebd5Sriastradh   _mesa_unlock_texture(ctx, texObj);
78501e04c3fSmrg
7867ec681f3Smrg   return true;
7873464ebd5Sriastradh}
7883464ebd5Sriastradh
78901e04c3fSmrg
7903464ebd5Sriastradhstatic void
7913464ebd5Sriastradhst_context_copy(struct st_context_iface *stctxi,
7923464ebd5Sriastradh                struct st_context_iface *stsrci, unsigned mask)
7933464ebd5Sriastradh{
7943464ebd5Sriastradh   struct st_context *st = (struct st_context *) stctxi;
7953464ebd5Sriastradh   struct st_context *src = (struct st_context *) stsrci;
7963464ebd5Sriastradh
7973464ebd5Sriastradh   _mesa_copy_context(src->ctx, st->ctx, mask);
7983464ebd5Sriastradh}
7993464ebd5Sriastradh
80001e04c3fSmrg
8017ec681f3Smrgstatic bool
8023464ebd5Sriastradhst_context_share(struct st_context_iface *stctxi,
8033464ebd5Sriastradh                 struct st_context_iface *stsrci)
8043464ebd5Sriastradh{
8053464ebd5Sriastradh   struct st_context *st = (struct st_context *) stctxi;
8063464ebd5Sriastradh   struct st_context *src = (struct st_context *) stsrci;
8073464ebd5Sriastradh
8083464ebd5Sriastradh   return _mesa_share_state(st->ctx, src->ctx);
8093464ebd5Sriastradh}
8103464ebd5Sriastradh
81101e04c3fSmrg
8123464ebd5Sriastradhstatic void
8133464ebd5Sriastradhst_context_destroy(struct st_context_iface *stctxi)
8143464ebd5Sriastradh{
8153464ebd5Sriastradh   struct st_context *st = (struct st_context *) stctxi;
8163464ebd5Sriastradh   st_destroy_context(st);
8173464ebd5Sriastradh}
8183464ebd5Sriastradh
81901e04c3fSmrg
82001e04c3fSmrgstatic void
82101e04c3fSmrgst_start_thread(struct st_context_iface *stctxi)
82201e04c3fSmrg{
82301e04c3fSmrg   struct st_context *st = (struct st_context *) stctxi;
82401e04c3fSmrg
82501e04c3fSmrg   _mesa_glthread_init(st->ctx);
82601e04c3fSmrg}
82701e04c3fSmrg
82801e04c3fSmrg
82901e04c3fSmrgstatic void
83001e04c3fSmrgst_thread_finish(struct st_context_iface *stctxi)
83101e04c3fSmrg{
83201e04c3fSmrg   struct st_context *st = (struct st_context *) stctxi;
83301e04c3fSmrg
83401e04c3fSmrg   _mesa_glthread_finish(st->ctx);
83501e04c3fSmrg}
83601e04c3fSmrg
83701e04c3fSmrg
8387ec681f3Smrgstatic void
8397ec681f3Smrgst_context_invalidate_state(struct st_context_iface *stctxi,
8407ec681f3Smrg                            unsigned flags)
8417ec681f3Smrg{
8427ec681f3Smrg   struct st_context *st = (struct st_context *) stctxi;
8437ec681f3Smrg
8447ec681f3Smrg   if (flags & ST_INVALIDATE_FS_SAMPLER_VIEWS)
8457ec681f3Smrg      st->dirty |= ST_NEW_FS_SAMPLER_VIEWS;
8467ec681f3Smrg   if (flags & ST_INVALIDATE_FS_CONSTBUF0)
8477ec681f3Smrg      st->dirty |= ST_NEW_FS_CONSTANTS;
8487ec681f3Smrg   if (flags & ST_INVALIDATE_VS_CONSTBUF0)
8497ec681f3Smrg      st->dirty |= ST_NEW_VS_CONSTANTS;
8507ec681f3Smrg   if (flags & ST_INVALIDATE_VERTEX_BUFFERS)
8517ec681f3Smrg      st->dirty |= ST_NEW_VERTEX_ARRAYS;
8527ec681f3Smrg}
8537ec681f3Smrg
8547ec681f3Smrg
85501e04c3fSmrgstatic void
85601e04c3fSmrgst_manager_destroy(struct st_manager *smapi)
85701e04c3fSmrg{
85801e04c3fSmrg   struct st_manager_private *smPriv = smapi->st_manager_private;
85901e04c3fSmrg
86001e04c3fSmrg   if (smPriv && smPriv->stfbi_ht) {
86101e04c3fSmrg      _mesa_hash_table_destroy(smPriv->stfbi_ht, NULL);
8627ec681f3Smrg      simple_mtx_destroy(&smPriv->st_mutex);
86301e04c3fSmrg      free(smPriv);
86401e04c3fSmrg      smapi->st_manager_private = NULL;
86501e04c3fSmrg   }
86601e04c3fSmrg}
86701e04c3fSmrg
86801e04c3fSmrg
8693464ebd5Sriastradhstatic struct st_context_iface *
8703464ebd5Sriastradhst_api_create_context(struct st_api *stapi, struct st_manager *smapi,
8713464ebd5Sriastradh                      const struct st_context_attribs *attribs,
872af69d88dSmrg                      enum st_context_error *error,
8733464ebd5Sriastradh                      struct st_context_iface *shared_stctxi)
8743464ebd5Sriastradh{
8753464ebd5Sriastradh   struct st_context *shared_ctx = (struct st_context *) shared_stctxi;
8763464ebd5Sriastradh   struct st_context *st;
8773464ebd5Sriastradh   struct pipe_context *pipe;
8787ec681f3Smrg   struct gl_config mode, *mode_ptr = &mode;
8793464ebd5Sriastradh   gl_api api;
88001e04c3fSmrg   bool no_error = false;
88101e04c3fSmrg   unsigned ctx_flags = PIPE_CONTEXT_PREFER_THREADED;
8823464ebd5Sriastradh
8833464ebd5Sriastradh   if (!(stapi->profile_mask & (1 << attribs->profile)))
8843464ebd5Sriastradh      return NULL;
8853464ebd5Sriastradh
8863464ebd5Sriastradh   switch (attribs->profile) {
8873464ebd5Sriastradh   case ST_PROFILE_DEFAULT:
888af69d88dSmrg      api = API_OPENGL_COMPAT;
8893464ebd5Sriastradh      break;
8903464ebd5Sriastradh   case ST_PROFILE_OPENGL_ES1:
8913464ebd5Sriastradh      api = API_OPENGLES;
8923464ebd5Sriastradh      break;
8933464ebd5Sriastradh   case ST_PROFILE_OPENGL_ES2:
8943464ebd5Sriastradh      api = API_OPENGLES2;
8953464ebd5Sriastradh      break;
8963464ebd5Sriastradh   case ST_PROFILE_OPENGL_CORE:
897af69d88dSmrg      api = API_OPENGL_CORE;
898af69d88dSmrg      break;
8993464ebd5Sriastradh   default:
900af69d88dSmrg      *error = ST_CONTEXT_ERROR_BAD_API;
9013464ebd5Sriastradh      return NULL;
9023464ebd5Sriastradh   }
9033464ebd5Sriastradh
9047ec681f3Smrg   _mesa_initialize();
9057ec681f3Smrg
90601e04c3fSmrg   /* Create a hash table for the framebuffer interface objects
90701e04c3fSmrg    * if it has not been created for this st manager.
90801e04c3fSmrg    */
90901e04c3fSmrg   if (smapi->st_manager_private == NULL) {
91001e04c3fSmrg      struct st_manager_private *smPriv;
91101e04c3fSmrg
91201e04c3fSmrg      smPriv = CALLOC_STRUCT(st_manager_private);
9137ec681f3Smrg      simple_mtx_init(&smPriv->st_mutex, mtx_plain);
91401e04c3fSmrg      smPriv->stfbi_ht = _mesa_hash_table_create(NULL,
91501e04c3fSmrg                                                 st_framebuffer_iface_hash,
91601e04c3fSmrg                                                 st_framebuffer_iface_equal);
91701e04c3fSmrg      smapi->st_manager_private = smPriv;
91801e04c3fSmrg      smapi->destroy = st_manager_destroy;
91901e04c3fSmrg   }
92001e04c3fSmrg
92101e04c3fSmrg   if (attribs->flags & ST_CONTEXT_FLAG_ROBUST_ACCESS)
92201e04c3fSmrg      ctx_flags |= PIPE_CONTEXT_ROBUST_BUFFER_ACCESS;
92301e04c3fSmrg
92401e04c3fSmrg   if (attribs->flags & ST_CONTEXT_FLAG_NO_ERROR)
92501e04c3fSmrg      no_error = true;
92601e04c3fSmrg
92701e04c3fSmrg   if (attribs->flags & ST_CONTEXT_FLAG_LOW_PRIORITY)
92801e04c3fSmrg      ctx_flags |= PIPE_CONTEXT_LOW_PRIORITY;
92901e04c3fSmrg   else if (attribs->flags & ST_CONTEXT_FLAG_HIGH_PRIORITY)
93001e04c3fSmrg      ctx_flags |= PIPE_CONTEXT_HIGH_PRIORITY;
93101e04c3fSmrg
932b9abf16eSmaya   if (attribs->flags & ST_CONTEXT_FLAG_RESET_NOTIFICATION_ENABLED)
933b9abf16eSmaya      ctx_flags |= PIPE_CONTEXT_LOSE_CONTEXT_ON_RESET;
934b9abf16eSmaya
93501e04c3fSmrg   pipe = smapi->screen->context_create(smapi->screen, NULL, ctx_flags);
936af69d88dSmrg   if (!pipe) {
937af69d88dSmrg      *error = ST_CONTEXT_ERROR_NO_MEMORY;
9383464ebd5Sriastradh      return NULL;
939af69d88dSmrg   }
9403464ebd5Sriastradh
9413464ebd5Sriastradh   st_visual_to_context_mode(&attribs->visual, &mode);
9427ec681f3Smrg   if (attribs->visual.color_format == PIPE_FORMAT_NONE)
94301e04c3fSmrg      mode_ptr = NULL;
94401e04c3fSmrg   st = st_create_context(api, pipe, mode_ptr, shared_ctx,
9457ec681f3Smrg                          &attribs->options, no_error,
9467ec681f3Smrg                          !!smapi->validate_egl_image);
9473464ebd5Sriastradh   if (!st) {
948af69d88dSmrg      *error = ST_CONTEXT_ERROR_NO_MEMORY;
9493464ebd5Sriastradh      pipe->destroy(pipe);
9503464ebd5Sriastradh      return NULL;
9513464ebd5Sriastradh   }
9523464ebd5Sriastradh
95301e04c3fSmrg   if (attribs->flags & ST_CONTEXT_FLAG_DEBUG) {
954af69d88dSmrg      if (!_mesa_set_debug_state_int(st->ctx, GL_DEBUG_OUTPUT, GL_TRUE)) {
955af69d88dSmrg         *error = ST_CONTEXT_ERROR_NO_MEMORY;
956af69d88dSmrg         return NULL;
957af69d88dSmrg      }
95801e04c3fSmrg
959af69d88dSmrg      st->ctx->Const.ContextFlags |= GL_CONTEXT_FLAG_DEBUG_BIT;
960af69d88dSmrg   }
961af69d88dSmrg
96201e04c3fSmrg   if (st->ctx->Const.ContextFlags & GL_CONTEXT_FLAG_DEBUG_BIT) {
96301e04c3fSmrg      st_update_debug_callback(st);
96401e04c3fSmrg   }
96501e04c3fSmrg
966af69d88dSmrg   if (attribs->flags & ST_CONTEXT_FLAG_FORWARD_COMPATIBLE)
967af69d88dSmrg      st->ctx->Const.ContextFlags |= GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT;
96801e04c3fSmrg   if (attribs->flags & ST_CONTEXT_FLAG_ROBUST_ACCESS) {
96901e04c3fSmrg      st->ctx->Const.ContextFlags |= GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB;
97001e04c3fSmrg      st->ctx->Const.RobustAccess = GL_TRUE;
97101e04c3fSmrg   }
97201e04c3fSmrg   if (attribs->flags & ST_CONTEXT_FLAG_RESET_NOTIFICATION_ENABLED) {
97301e04c3fSmrg      st->ctx->Const.ResetStrategy = GL_LOSE_CONTEXT_ON_RESET_ARB;
97401e04c3fSmrg      st_install_device_reset_callback(st);
97501e04c3fSmrg   }
97601e04c3fSmrg
97701e04c3fSmrg   if (attribs->flags & ST_CONTEXT_FLAG_RELEASE_NONE)
97801e04c3fSmrg       st->ctx->Const.ContextReleaseBehavior = GL_NONE;
979af69d88dSmrg
9803464ebd5Sriastradh   /* need to perform version check */
9813464ebd5Sriastradh   if (attribs->major > 1 || attribs->minor > 0) {
982af69d88dSmrg      /* Is the actual version less than the requested version?
983af69d88dSmrg       */
98401e04c3fSmrg      if (st->ctx->Version < attribs->major * 10U + attribs->minor) {
98501e04c3fSmrg         *error = ST_CONTEXT_ERROR_BAD_VERSION;
9863464ebd5Sriastradh         st_destroy_context(st);
9873464ebd5Sriastradh         return NULL;
9883464ebd5Sriastradh      }
9893464ebd5Sriastradh   }
9903464ebd5Sriastradh
9917ec681f3Smrg   st->can_scissor_clear = !!st->screen->get_param(st->screen, PIPE_CAP_CLEAR_SCISSORED);
9927ec681f3Smrg
9933464ebd5Sriastradh   st->invalidate_on_gl_viewport =
9943464ebd5Sriastradh      smapi->get_param(smapi, ST_MANAGER_BROKEN_INVALIDATE);
9953464ebd5Sriastradh
9963464ebd5Sriastradh   st->iface.destroy = st_context_destroy;
9973464ebd5Sriastradh   st->iface.flush = st_context_flush;
9983464ebd5Sriastradh   st->iface.teximage = st_context_teximage;
9993464ebd5Sriastradh   st->iface.copy = st_context_copy;
10003464ebd5Sriastradh   st->iface.share = st_context_share;
100101e04c3fSmrg   st->iface.start_thread = st_start_thread;
100201e04c3fSmrg   st->iface.thread_finish = st_thread_finish;
10037ec681f3Smrg   st->iface.invalidate_state = st_context_invalidate_state;
10043464ebd5Sriastradh   st->iface.st_context_private = (void *) smapi;
1005af69d88dSmrg   st->iface.cso_context = st->cso_context;
1006af69d88dSmrg   st->iface.pipe = st->pipe;
100701e04c3fSmrg   st->iface.state_manager = smapi;
10083464ebd5Sriastradh
10097ec681f3Smrg   if (st->ctx->IntelBlackholeRender &&
10107ec681f3Smrg       st->screen->get_param(st->screen, PIPE_CAP_FRONTEND_NOOP))
10117ec681f3Smrg      st->pipe->set_frontend_noop(st->pipe, st->ctx->IntelBlackholeRender);
10127ec681f3Smrg
1013af69d88dSmrg   *error = ST_CONTEXT_SUCCESS;
10143464ebd5Sriastradh   return &st->iface;
10153464ebd5Sriastradh}
10163464ebd5Sriastradh
101701e04c3fSmrg
10183464ebd5Sriastradhstatic struct st_context_iface *
10193464ebd5Sriastradhst_api_get_current(struct st_api *stapi)
10203464ebd5Sriastradh{
10213464ebd5Sriastradh   GET_CURRENT_CONTEXT(ctx);
102201e04c3fSmrg   struct st_context *st = ctx ? ctx->st : NULL;
10233464ebd5Sriastradh
102401e04c3fSmrg   return st ? &st->iface : NULL;
10253464ebd5Sriastradh}
10263464ebd5Sriastradh
102701e04c3fSmrg
10283464ebd5Sriastradhstatic struct st_framebuffer *
1029af69d88dSmrgst_framebuffer_reuse_or_create(struct st_context *st,
1030af69d88dSmrg                               struct gl_framebuffer *fb,
10313464ebd5Sriastradh                               struct st_framebuffer_iface *stfbi)
10323464ebd5Sriastradh{
103301e04c3fSmrg   struct st_framebuffer *cur = NULL, *stfb = NULL;
103401e04c3fSmrg
103501e04c3fSmrg   if (!stfbi)
103601e04c3fSmrg      return NULL;
10373464ebd5Sriastradh
103801e04c3fSmrg   /* Check if there is already a framebuffer object for the specified
103901e04c3fSmrg    * framebuffer interface in this context. If there is one, use it.
104001e04c3fSmrg    */
104101e04c3fSmrg   LIST_FOR_EACH_ENTRY(cur, &st->winsys_buffers, head) {
104201e04c3fSmrg      if (cur->iface_ID == stfbi->ID) {
104301e04c3fSmrg         st_framebuffer_reference(&stfb, cur);
104401e04c3fSmrg         break;
104501e04c3fSmrg      }
10463464ebd5Sriastradh   }
104701e04c3fSmrg
104801e04c3fSmrg   /* If there is not already a framebuffer object, create one */
104901e04c3fSmrg   if (stfb == NULL) {
105001e04c3fSmrg      cur = st_framebuffer_create(st, stfbi);
105101e04c3fSmrg
105201e04c3fSmrg      if (cur) {
105301e04c3fSmrg         /* add the referenced framebuffer interface object to
105401e04c3fSmrg          * the framebuffer interface object hash table.
105501e04c3fSmrg          */
105601e04c3fSmrg         if (!st_framebuffer_iface_insert(stfbi->state_manager, stfbi)) {
105701e04c3fSmrg            st_framebuffer_reference(&cur, NULL);
105801e04c3fSmrg            return NULL;
105901e04c3fSmrg         }
106001e04c3fSmrg
106101e04c3fSmrg         /* add to the context's winsys buffers list */
10627ec681f3Smrg         list_add(&cur->head, &st->winsys_buffers);
106301e04c3fSmrg
106401e04c3fSmrg         st_framebuffer_reference(&stfb, cur);
106501e04c3fSmrg      }
10663464ebd5Sriastradh   }
10673464ebd5Sriastradh
10683464ebd5Sriastradh   return stfb;
10693464ebd5Sriastradh}
10703464ebd5Sriastradh
107101e04c3fSmrg
10727ec681f3Smrgstatic bool
10733464ebd5Sriastradhst_api_make_current(struct st_api *stapi, struct st_context_iface *stctxi,
10743464ebd5Sriastradh                    struct st_framebuffer_iface *stdrawi,
10753464ebd5Sriastradh                    struct st_framebuffer_iface *streadi)
10763464ebd5Sriastradh{
10773464ebd5Sriastradh   struct st_context *st = (struct st_context *) stctxi;
10783464ebd5Sriastradh   struct st_framebuffer *stdraw, *stread;
10797ec681f3Smrg   bool ret;
10803464ebd5Sriastradh
10813464ebd5Sriastradh   if (st) {
10823464ebd5Sriastradh      /* reuse or create the draw fb */
1083af69d88dSmrg      stdraw = st_framebuffer_reuse_or_create(st,
1084af69d88dSmrg            st->ctx->WinSysDrawBuffer, stdrawi);
10853464ebd5Sriastradh      if (streadi != stdrawi) {
10863464ebd5Sriastradh         /* do the same for the read fb */
1087af69d88dSmrg         stread = st_framebuffer_reuse_or_create(st,
1088af69d88dSmrg               st->ctx->WinSysReadBuffer, streadi);
10893464ebd5Sriastradh      }
10903464ebd5Sriastradh      else {
10913464ebd5Sriastradh         stread = NULL;
10923464ebd5Sriastradh         /* reuse the draw fb for the read fb */
10933464ebd5Sriastradh         if (stdraw)
10943464ebd5Sriastradh            st_framebuffer_reference(&stread, stdraw);
10953464ebd5Sriastradh      }
10963464ebd5Sriastradh
10977ec681f3Smrg      /* If framebuffers were asked for, we'd better have allocated them */
10987ec681f3Smrg      if ((stdrawi && !stdraw) || (streadi && !stread))
10997ec681f3Smrg         return false;
11007ec681f3Smrg
11013464ebd5Sriastradh      if (stdraw && stread) {
11023464ebd5Sriastradh         st_framebuffer_validate(stdraw, st);
11033464ebd5Sriastradh         if (stread != stdraw)
11043464ebd5Sriastradh            st_framebuffer_validate(stread, st);
11053464ebd5Sriastradh
11063464ebd5Sriastradh         ret = _mesa_make_current(st->ctx, &stdraw->Base, &stread->Base);
1107af69d88dSmrg
1108af69d88dSmrg         st->draw_stamp = stdraw->stamp - 1;
1109af69d88dSmrg         st->read_stamp = stread->stamp - 1;
1110af69d88dSmrg         st_context_validate(st, stdraw, stread);
11113464ebd5Sriastradh      }
11123464ebd5Sriastradh      else {
11133464ebd5Sriastradh         struct gl_framebuffer *incomplete = _mesa_get_incomplete_framebuffer();
11143464ebd5Sriastradh         ret = _mesa_make_current(st->ctx, incomplete, incomplete);
11153464ebd5Sriastradh      }
11163464ebd5Sriastradh
11173464ebd5Sriastradh      st_framebuffer_reference(&stdraw, NULL);
11183464ebd5Sriastradh      st_framebuffer_reference(&stread, NULL);
111901e04c3fSmrg
112001e04c3fSmrg      /* Purge the context's winsys_buffers list in case any
112101e04c3fSmrg       * of the referenced drawables no longer exist.
112201e04c3fSmrg       */
112301e04c3fSmrg      st_framebuffers_purge(st);
11243464ebd5Sriastradh   }
11253464ebd5Sriastradh   else {
112601e04c3fSmrg      GET_CURRENT_CONTEXT(ctx);
112701e04c3fSmrg
1128b9abf16eSmaya      if (ctx) {
1129b9abf16eSmaya         /* Before releasing the context, release its associated
1130b9abf16eSmaya          * winsys buffers first. Then purge the context's winsys buffers list
1131b9abf16eSmaya          * to free the resources of any winsys buffers that no longer have
1132b9abf16eSmaya          * an existing drawable.
1133b9abf16eSmaya          */
1134b9abf16eSmaya         ret = _mesa_make_current(ctx, NULL, NULL);
113501e04c3fSmrg         st_framebuffers_purge(ctx->st);
1136b9abf16eSmaya      }
1137b9abf16eSmaya
1138b9abf16eSmaya      ret = _mesa_make_current(NULL, NULL, NULL);
11393464ebd5Sriastradh   }
11403464ebd5Sriastradh
11413464ebd5Sriastradh   return ret;
11423464ebd5Sriastradh}
11433464ebd5Sriastradh
11443464ebd5Sriastradh
11453464ebd5Sriastradhstatic void
11463464ebd5Sriastradhst_api_destroy(struct st_api *stapi)
11473464ebd5Sriastradh{
11483464ebd5Sriastradh}
11493464ebd5Sriastradh
115001e04c3fSmrg
11513464ebd5Sriastradh/**
11523464ebd5Sriastradh * Flush the front buffer if the current context renders to the front buffer.
11533464ebd5Sriastradh */
11543464ebd5Sriastradhvoid
11553464ebd5Sriastradhst_manager_flush_frontbuffer(struct st_context *st)
11563464ebd5Sriastradh{
11573464ebd5Sriastradh   struct st_framebuffer *stfb = st_ws_framebuffer(st->ctx->DrawBuffer);
11583464ebd5Sriastradh   struct st_renderbuffer *strb = NULL;
11593464ebd5Sriastradh
1160b9abf16eSmaya   if (!stfb)
1161b9abf16eSmaya      return;
1162b9abf16eSmaya
1163b9abf16eSmaya   /* If the context uses a doublebuffered visual, but the buffer is
1164b9abf16eSmaya    * single-buffered, guess that it's a pbuffer, which doesn't need
1165b9abf16eSmaya    * flushing.
1166b9abf16eSmaya    */
1167b9abf16eSmaya   if (st->ctx->Visual.doubleBufferMode &&
1168b9abf16eSmaya       !stfb->Base.Visual.doubleBufferMode)
1169b9abf16eSmaya      return;
1170b9abf16eSmaya
11717ec681f3Smrg   /* Check front buffer used at the GL API level. */
11727ec681f3Smrg   enum st_attachment_type statt = ST_ATTACHMENT_FRONT_LEFT;
1173b9abf16eSmaya   strb = st_renderbuffer(stfb->Base.Attachment[BUFFER_FRONT_LEFT].
1174b9abf16eSmaya                          Renderbuffer);
11757ec681f3Smrg   if (!strb) {
11767ec681f3Smrg       /* Check back buffer redirected by EGL_KHR_mutable_render_buffer. */
11777ec681f3Smrg       statt = ST_ATTACHMENT_BACK_LEFT;
11787ec681f3Smrg       strb = st_renderbuffer(stfb->Base.Attachment[BUFFER_BACK_LEFT].
11797ec681f3Smrg                              Renderbuffer);
11807ec681f3Smrg   }
11813464ebd5Sriastradh
118201e04c3fSmrg   /* Do we have a front color buffer and has it been drawn to since last
118301e04c3fSmrg    * frontbuffer flush?
118401e04c3fSmrg    */
11857ec681f3Smrg   if (strb && strb->defined &&
11867ec681f3Smrg       stfb->iface->flush_front(&st->iface, stfb->iface, statt)) {
118701e04c3fSmrg      strb->defined = GL_FALSE;
11883464ebd5Sriastradh
118901e04c3fSmrg      /* Trigger an update of strb->defined on next draw */
119001e04c3fSmrg      st->dirty |= ST_NEW_FB_STATE;
119101e04c3fSmrg   }
11923464ebd5Sriastradh}
11933464ebd5Sriastradh
119401e04c3fSmrg
11953464ebd5Sriastradh/**
11963464ebd5Sriastradh * Re-validate the framebuffers.
11973464ebd5Sriastradh */
11983464ebd5Sriastradhvoid
11993464ebd5Sriastradhst_manager_validate_framebuffers(struct st_context *st)
12003464ebd5Sriastradh{
12013464ebd5Sriastradh   struct st_framebuffer *stdraw = st_ws_framebuffer(st->ctx->DrawBuffer);
12023464ebd5Sriastradh   struct st_framebuffer *stread = st_ws_framebuffer(st->ctx->ReadBuffer);
12033464ebd5Sriastradh
12043464ebd5Sriastradh   if (stdraw)
12053464ebd5Sriastradh      st_framebuffer_validate(stdraw, st);
12063464ebd5Sriastradh   if (stread && stread != stdraw)
12073464ebd5Sriastradh      st_framebuffer_validate(stread, st);
1208af69d88dSmrg
1209af69d88dSmrg   st_context_validate(st, stdraw, stread);
12103464ebd5Sriastradh}
12113464ebd5Sriastradh
121201e04c3fSmrg
121301e04c3fSmrg/**
121401e04c3fSmrg * Flush any outstanding swapbuffers on the current draw framebuffer.
121501e04c3fSmrg */
121601e04c3fSmrgvoid
121701e04c3fSmrgst_manager_flush_swapbuffers(void)
121801e04c3fSmrg{
121901e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
122001e04c3fSmrg   struct st_context *st = (ctx) ? ctx->st : NULL;
122101e04c3fSmrg   struct st_framebuffer *stfb;
122201e04c3fSmrg
122301e04c3fSmrg   if (!st)
122401e04c3fSmrg      return;
122501e04c3fSmrg
122601e04c3fSmrg   stfb = st_ws_framebuffer(ctx->DrawBuffer);
122701e04c3fSmrg   if (!stfb || !stfb->iface->flush_swapbuffers)
122801e04c3fSmrg      return;
122901e04c3fSmrg
123001e04c3fSmrg   stfb->iface->flush_swapbuffers(&st->iface, stfb->iface);
123101e04c3fSmrg}
123201e04c3fSmrg
123301e04c3fSmrg
12343464ebd5Sriastradh/**
123501e04c3fSmrg * Add a color renderbuffer on demand.  The FBO must correspond to a window,
123601e04c3fSmrg * not a user-created FBO.
12373464ebd5Sriastradh */
12387ec681f3Smrgbool
12393464ebd5Sriastradhst_manager_add_color_renderbuffer(struct st_context *st,
12403464ebd5Sriastradh                                  struct gl_framebuffer *fb,
12413464ebd5Sriastradh                                  gl_buffer_index idx)
12423464ebd5Sriastradh{
12433464ebd5Sriastradh   struct st_framebuffer *stfb = st_ws_framebuffer(fb);
12443464ebd5Sriastradh
12453464ebd5Sriastradh   /* FBO */
12463464ebd5Sriastradh   if (!stfb)
12477ec681f3Smrg      return false;
12483464ebd5Sriastradh
124901e04c3fSmrg   assert(_mesa_is_winsys_fbo(fb));
125001e04c3fSmrg
12513464ebd5Sriastradh   if (stfb->Base.Attachment[idx].Renderbuffer)
12527ec681f3Smrg      return true;
12533464ebd5Sriastradh
12543464ebd5Sriastradh   switch (idx) {
12553464ebd5Sriastradh   case BUFFER_FRONT_LEFT:
12563464ebd5Sriastradh   case BUFFER_BACK_LEFT:
12573464ebd5Sriastradh   case BUFFER_FRONT_RIGHT:
12583464ebd5Sriastradh   case BUFFER_BACK_RIGHT:
12593464ebd5Sriastradh      break;
12603464ebd5Sriastradh   default:
12617ec681f3Smrg      return false;
12623464ebd5Sriastradh   }
12633464ebd5Sriastradh
1264b9abf16eSmaya   if (!st_framebuffer_add_renderbuffer(stfb, idx,
1265b9abf16eSmaya                                        stfb->Base.Visual.sRGBCapable))
12667ec681f3Smrg      return false;
12673464ebd5Sriastradh
12683464ebd5Sriastradh   st_framebuffer_update_attachments(stfb);
1269af69d88dSmrg
1270af69d88dSmrg   /*
12717ec681f3Smrg    * Force a call to the frontend manager to validate the
1272af69d88dSmrg    * new renderbuffer. It might be that there is a window system
1273af69d88dSmrg    * renderbuffer available.
1274af69d88dSmrg    */
127501e04c3fSmrg   if (stfb->iface)
1276af69d88dSmrg      stfb->iface_stamp = p_atomic_read(&stfb->iface->stamp) - 1;
1277af69d88dSmrg
127801e04c3fSmrg   st_invalidate_buffers(st);
12793464ebd5Sriastradh
12807ec681f3Smrg   return true;
12813464ebd5Sriastradh}
12823464ebd5Sriastradh
128301e04c3fSmrg
128401e04c3fSmrgstatic unsigned
128501e04c3fSmrgget_version(struct pipe_screen *screen,
128601e04c3fSmrg            struct st_config_options *options, gl_api api)
1287af69d88dSmrg{
1288af69d88dSmrg   struct gl_constants consts = {0};
1289af69d88dSmrg   struct gl_extensions extensions = {0};
1290af69d88dSmrg   GLuint version;
1291af69d88dSmrg
129201e04c3fSmrg   if (_mesa_override_gl_version_contextless(&consts, &api, &version)) {
1293af69d88dSmrg      return version;
1294af69d88dSmrg   }
1295af69d88dSmrg
1296af69d88dSmrg   _mesa_init_constants(&consts, api);
1297af69d88dSmrg   _mesa_init_extensions(&extensions);
1298af69d88dSmrg
1299b9abf16eSmaya   st_init_limits(screen, &consts, &extensions);
130001e04c3fSmrg   st_init_extensions(screen, &consts, &extensions, options, api);
13017ec681f3Smrg   version = _mesa_get_version(&extensions, &consts, api);
13027ec681f3Smrg   free(consts.SpirVExtensions);
13037ec681f3Smrg   return version;
1304af69d88dSmrg}
1305af69d88dSmrg
130601e04c3fSmrg
1307af69d88dSmrgstatic void
1308af69d88dSmrgst_api_query_versions(struct st_api *stapi, struct st_manager *sm,
1309af69d88dSmrg                      struct st_config_options *options,
1310af69d88dSmrg                      int *gl_core_version,
1311af69d88dSmrg                      int *gl_compat_version,
1312af69d88dSmrg                      int *gl_es1_version,
1313af69d88dSmrg                      int *gl_es2_version)
1314af69d88dSmrg{
1315af69d88dSmrg   *gl_core_version = get_version(sm->screen, options, API_OPENGL_CORE);
1316af69d88dSmrg   *gl_compat_version = get_version(sm->screen, options, API_OPENGL_COMPAT);
1317af69d88dSmrg   *gl_es1_version = get_version(sm->screen, options, API_OPENGLES);
1318af69d88dSmrg   *gl_es2_version = get_version(sm->screen, options, API_OPENGLES2);
1319af69d88dSmrg}
1320af69d88dSmrg
132101e04c3fSmrg
13223464ebd5Sriastradhstatic const struct st_api st_gl_api = {
132301e04c3fSmrg   .name = "Mesa " PACKAGE_VERSION,
132401e04c3fSmrg   .api = ST_API_OPENGL,
132501e04c3fSmrg   .profile_mask = ST_PROFILE_DEFAULT_MASK |
132601e04c3fSmrg                   ST_PROFILE_OPENGL_CORE_MASK |
132701e04c3fSmrg                   ST_PROFILE_OPENGL_ES1_MASK |
132801e04c3fSmrg                   ST_PROFILE_OPENGL_ES2_MASK |
132901e04c3fSmrg                   0,
133001e04c3fSmrg   .feature_mask = ST_API_FEATURE_MS_VISUALS_MASK,
133101e04c3fSmrg   .destroy = st_api_destroy,
133201e04c3fSmrg   .query_versions = st_api_query_versions,
133301e04c3fSmrg   .create_context = st_api_create_context,
133401e04c3fSmrg   .make_current = st_api_make_current,
133501e04c3fSmrg   .get_current = st_api_get_current,
133601e04c3fSmrg   .destroy_drawable = st_api_destroy_drawable,
13373464ebd5Sriastradh};
13383464ebd5Sriastradh
133901e04c3fSmrg
13403464ebd5Sriastradhstruct st_api *
13413464ebd5Sriastradhst_gl_api_create(void)
13423464ebd5Sriastradh{
13433464ebd5Sriastradh   return (struct st_api *) &st_gl_api;
13443464ebd5Sriastradh}
1345