xref: /aosp_15_r20/external/mesa3d/src/mesa/state_tracker/st_manager.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Mesa 3-D graphics library
3  *
4  * Copyright (C) 2010 LunarG Inc.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included
14  * in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  *
24  * Authors:
25  *    Chia-I Wu <[email protected]>
26  */
27 
28 #include "main/mtypes.h"
29 #include "main/extensions.h"
30 #include "main/context.h"
31 #include "main/debug_output.h"
32 #include "main/framebuffer.h"
33 #include "main/glthread.h"
34 #include "main/texobj.h"
35 #include "main/teximage.h"
36 #include "main/texstate.h"
37 #include "main/errors.h"
38 #include "main/framebuffer.h"
39 #include "main/fbobject.h"
40 #include "main/renderbuffer.h"
41 #include "main/version.h"
42 #include "util/hash_table.h"
43 #include "st_texture.h"
44 
45 #include "st_context.h"
46 #include "st_debug.h"
47 #include "st_extensions.h"
48 #include "st_format.h"
49 #include "st_cb_bitmap.h"
50 #include "st_cb_flush.h"
51 #include "st_manager.h"
52 #include "st_sampler_view.h"
53 #include "st_util.h"
54 
55 #include "pipe/p_context.h"
56 #include "pipe/p_screen.h"
57 #include "util/format/u_format.h"
58 #include "util/u_helpers.h"
59 #include "util/u_pointer.h"
60 #include "util/u_inlines.h"
61 #include "util/u_atomic.h"
62 #include "util/u_surface.h"
63 #include "util/list.h"
64 #include "util/u_memory.h"
65 #include "util/perf/cpu_trace.h"
66 
67 struct hash_table;
68 
69 struct st_screen
70 {
71    struct hash_table *drawable_ht; /* pipe_frontend_drawable objects hash table */
72    simple_mtx_t st_mutex;
73 };
74 
75 /**
76  * Cast wrapper to convert a struct gl_framebuffer to an gl_framebuffer.
77  * Return NULL if the struct gl_framebuffer is a user-created framebuffer.
78  * We'll only return non-null for window system framebuffers.
79  * Note that this function may fail.
80  */
81 static inline struct gl_framebuffer *
st_ws_framebuffer(struct gl_framebuffer * fb)82 st_ws_framebuffer(struct gl_framebuffer *fb)
83 {
84    /* FBO cannot be casted.  See st_new_framebuffer */
85    if (fb && _mesa_is_winsys_fbo(fb) &&
86        fb != _mesa_get_incomplete_framebuffer())
87       return fb;
88    return NULL;
89 }
90 
91 /**
92  * Map an attachment to a buffer index.
93  */
94 static inline gl_buffer_index
attachment_to_buffer_index(enum st_attachment_type statt)95 attachment_to_buffer_index(enum st_attachment_type statt)
96 {
97    gl_buffer_index index;
98 
99    switch (statt) {
100    case ST_ATTACHMENT_FRONT_LEFT:
101       index = BUFFER_FRONT_LEFT;
102       break;
103    case ST_ATTACHMENT_BACK_LEFT:
104       index = BUFFER_BACK_LEFT;
105       break;
106    case ST_ATTACHMENT_FRONT_RIGHT:
107       index = BUFFER_FRONT_RIGHT;
108       break;
109    case ST_ATTACHMENT_BACK_RIGHT:
110       index = BUFFER_BACK_RIGHT;
111       break;
112    case ST_ATTACHMENT_DEPTH_STENCIL:
113       index = BUFFER_DEPTH;
114       break;
115    case ST_ATTACHMENT_ACCUM:
116       index = BUFFER_ACCUM;
117       break;
118    default:
119       index = BUFFER_COUNT;
120       break;
121    }
122 
123    return index;
124 }
125 
126 
127 /**
128  * Map a buffer index to an attachment.
129  */
130 static inline enum st_attachment_type
buffer_index_to_attachment(gl_buffer_index index)131 buffer_index_to_attachment(gl_buffer_index index)
132 {
133    enum st_attachment_type statt;
134 
135    switch (index) {
136    case BUFFER_FRONT_LEFT:
137       statt = ST_ATTACHMENT_FRONT_LEFT;
138       break;
139    case BUFFER_BACK_LEFT:
140       statt = ST_ATTACHMENT_BACK_LEFT;
141       break;
142    case BUFFER_FRONT_RIGHT:
143       statt = ST_ATTACHMENT_FRONT_RIGHT;
144       break;
145    case BUFFER_BACK_RIGHT:
146       statt = ST_ATTACHMENT_BACK_RIGHT;
147       break;
148    case BUFFER_DEPTH:
149       statt = ST_ATTACHMENT_DEPTH_STENCIL;
150       break;
151    case BUFFER_ACCUM:
152       statt = ST_ATTACHMENT_ACCUM;
153       break;
154    default:
155       statt = ST_ATTACHMENT_INVALID;
156       break;
157    }
158 
159    return statt;
160 }
161 
162 
163 /**
164  * Make sure a context picks up the latest cached state of the
165  * drawables it binds to.
166  */
167 static void
st_context_validate(struct st_context * st,struct gl_framebuffer * stdraw,struct gl_framebuffer * stread)168 st_context_validate(struct st_context *st,
169                     struct gl_framebuffer *stdraw,
170                     struct gl_framebuffer *stread)
171 {
172     if (stdraw && stdraw->stamp != st->draw_stamp) {
173        st->ctx->NewDriverState |= ST_NEW_FRAMEBUFFER;
174        _mesa_resize_framebuffer(st->ctx, stdraw,
175                                 stdraw->Width,
176                                 stdraw->Height);
177        st->draw_stamp = stdraw->stamp;
178     }
179 
180     if (stread && stread->stamp != st->read_stamp) {
181        if (stread != stdraw) {
182           st->ctx->NewDriverState |= ST_NEW_FRAMEBUFFER;
183           _mesa_resize_framebuffer(st->ctx, stread,
184                                    stread->Width,
185                                    stread->Height);
186        }
187        st->read_stamp = stread->stamp;
188     }
189 }
190 
191 
192 void
st_set_ws_renderbuffer_surface(struct gl_renderbuffer * rb,struct pipe_surface * surf)193 st_set_ws_renderbuffer_surface(struct gl_renderbuffer *rb,
194                                struct pipe_surface *surf)
195 {
196    pipe_surface_reference(&rb->surface_srgb, NULL);
197    pipe_surface_reference(&rb->surface_linear, NULL);
198 
199    if (util_format_is_srgb(surf->format))
200       pipe_surface_reference(&rb->surface_srgb, surf);
201    else
202       pipe_surface_reference(&rb->surface_linear, surf);
203 
204    rb->surface = surf; /* just assign, don't ref */
205    pipe_resource_reference(&rb->texture, surf->texture);
206 
207    rb->Width = surf->width;
208    rb->Height = surf->height;
209 }
210 
211 
212 /**
213  * Validate a framebuffer to make sure up-to-date pipe_textures are used.
214  * The context is only used for creating pipe surfaces and for calling
215  * _mesa_resize_framebuffer().
216  * (That should probably be rethought, since those surfaces become
217  * drawable state, not context state, and can be freed by another pipe
218  * context).
219  */
220 static void
st_framebuffer_validate(struct gl_framebuffer * stfb,struct st_context * st)221 st_framebuffer_validate(struct gl_framebuffer *stfb,
222                         struct st_context *st)
223 {
224    struct pipe_resource *textures[ST_ATTACHMENT_COUNT];
225    struct pipe_resource *resolve = NULL;
226    uint width, height;
227    unsigned i;
228    bool changed = false;
229    int32_t new_stamp;
230 
231    new_stamp = p_atomic_read(&stfb->drawable->stamp);
232    if (stfb->drawable_stamp == new_stamp)
233       return;
234 
235    memset(textures, 0, stfb->num_statts * sizeof(textures[0]));
236 
237    /* validate the fb */
238    do {
239       if (!stfb->drawable->validate(st, stfb->drawable, stfb->statts,
240                                  stfb->num_statts, textures, &resolve))
241          return;
242 
243       stfb->drawable_stamp = new_stamp;
244       new_stamp = p_atomic_read(&stfb->drawable->stamp);
245    } while(stfb->drawable_stamp != new_stamp);
246 
247    width = stfb->Width;
248    height = stfb->Height;
249 
250    for (i = 0; i < stfb->num_statts; i++) {
251       struct gl_renderbuffer *rb;
252       struct pipe_surface *ps, surf_tmpl;
253       gl_buffer_index idx;
254 
255       if (!textures[i])
256          continue;
257 
258       idx = attachment_to_buffer_index(stfb->statts[i]);
259       if (idx >= BUFFER_COUNT) {
260          pipe_resource_reference(&textures[i], NULL);
261          continue;
262       }
263 
264       rb = stfb->Attachment[idx].Renderbuffer;
265       assert(rb);
266       if (rb->texture == textures[i] &&
267           rb->Width == textures[i]->width0 &&
268           rb->Height == textures[i]->height0) {
269          pipe_resource_reference(&textures[i], NULL);
270          continue;
271       }
272 
273       u_surface_default_template(&surf_tmpl, textures[i]);
274       ps = st->pipe->create_surface(st->pipe, textures[i], &surf_tmpl);
275       if (ps) {
276          st_set_ws_renderbuffer_surface(rb, ps);
277          pipe_surface_reference(&ps, NULL);
278 
279          changed = true;
280 
281          width = rb->Width;
282          height = rb->Height;
283       }
284 
285       pipe_resource_reference(&textures[i], NULL);
286    }
287 
288    changed |= resolve != stfb->resolve;
289    /* ref is removed here */
290    pipe_resource_reference(&stfb->resolve, NULL);
291    /* ref is taken here */
292    stfb->resolve = resolve;
293 
294    if (changed) {
295       ++stfb->stamp;
296       _mesa_resize_framebuffer(st->ctx, stfb, width, height);
297    }
298 }
299 
300 /**
301  * Return true if the visual has the specified buffers.
302  */
303 static inline bool
st_visual_have_buffers(const struct st_visual * visual,unsigned mask)304 st_visual_have_buffers(const struct st_visual *visual, unsigned mask)
305 {
306    return ((visual->buffer_mask & mask) == mask);
307 }
308 
309 /**
310  * Update the attachments to validate by looping the existing renderbuffers.
311  */
312 static void
st_framebuffer_update_attachments(struct gl_framebuffer * stfb)313 st_framebuffer_update_attachments(struct gl_framebuffer *stfb)
314 {
315    gl_buffer_index idx;
316 
317    stfb->num_statts = 0;
318 
319    for (enum st_attachment_type i = 0; i < ST_ATTACHMENT_COUNT; i++)
320       stfb->statts[i] = ST_ATTACHMENT_INVALID;
321 
322    for (idx = 0; idx < BUFFER_COUNT; idx++) {
323       struct gl_renderbuffer *rb;
324       enum st_attachment_type statt;
325 
326       rb = stfb->Attachment[idx].Renderbuffer;
327       if (!rb || rb->software)
328          continue;
329 
330       statt = buffer_index_to_attachment(idx);
331       if (statt != ST_ATTACHMENT_INVALID &&
332           st_visual_have_buffers(stfb->drawable->visual, 1 << statt))
333          stfb->statts[stfb->num_statts++] = statt;
334    }
335    stfb->stamp++;
336 }
337 
338 /**
339  * Allocate a renderbuffer for an on-screen window (not a user-created
340  * renderbuffer).  The window system code determines the format.
341  */
342 static struct gl_renderbuffer *
st_new_renderbuffer_fb(enum pipe_format format,unsigned samples,bool sw)343 st_new_renderbuffer_fb(enum pipe_format format, unsigned samples, bool sw)
344 {
345    struct gl_renderbuffer *rb;
346 
347    rb = CALLOC_STRUCT(gl_renderbuffer);
348    if (!rb) {
349       _mesa_error(NULL, GL_OUT_OF_MEMORY, "creating renderbuffer");
350       return NULL;
351    }
352 
353    _mesa_init_renderbuffer(rb, 0);
354    rb->NumSamples = samples;
355    rb->NumStorageSamples = samples;
356    rb->Format = st_pipe_format_to_mesa_format(format);
357    rb->_BaseFormat = _mesa_get_format_base_format(rb->Format);
358    rb->software = sw;
359 
360    switch (format) {
361    case PIPE_FORMAT_B10G10R10A2_UNORM:
362    case PIPE_FORMAT_R10G10B10A2_UNORM:
363       rb->InternalFormat = GL_RGB10_A2;
364       break;
365    case PIPE_FORMAT_R10G10B10X2_UNORM:
366    case PIPE_FORMAT_B10G10R10X2_UNORM:
367       rb->InternalFormat = GL_RGB10;
368       break;
369    case PIPE_FORMAT_R8G8B8A8_UNORM:
370    case PIPE_FORMAT_B8G8R8A8_UNORM:
371    case PIPE_FORMAT_A8R8G8B8_UNORM:
372       rb->InternalFormat = GL_RGBA8;
373       break;
374    case PIPE_FORMAT_R8G8B8X8_UNORM:
375    case PIPE_FORMAT_B8G8R8X8_UNORM:
376    case PIPE_FORMAT_X8R8G8B8_UNORM:
377    case PIPE_FORMAT_R8G8B8_UNORM:
378       rb->InternalFormat = GL_RGB8;
379       break;
380    case PIPE_FORMAT_R8G8B8A8_SRGB:
381    case PIPE_FORMAT_B8G8R8A8_SRGB:
382    case PIPE_FORMAT_A8R8G8B8_SRGB:
383       rb->InternalFormat = GL_SRGB8_ALPHA8;
384       break;
385    case PIPE_FORMAT_R8G8B8X8_SRGB:
386    case PIPE_FORMAT_B8G8R8X8_SRGB:
387    case PIPE_FORMAT_X8R8G8B8_SRGB:
388       rb->InternalFormat = GL_SRGB8;
389       break;
390    case PIPE_FORMAT_B5G5R5A1_UNORM:
391       rb->InternalFormat = GL_RGB5_A1;
392       break;
393    case PIPE_FORMAT_B4G4R4A4_UNORM:
394       rb->InternalFormat = GL_RGBA4;
395       break;
396    case PIPE_FORMAT_B5G6R5_UNORM:
397       rb->InternalFormat = GL_RGB565;
398       break;
399    case PIPE_FORMAT_Z16_UNORM:
400       rb->InternalFormat = GL_DEPTH_COMPONENT16;
401       break;
402    case PIPE_FORMAT_Z32_UNORM:
403       rb->InternalFormat = GL_DEPTH_COMPONENT32;
404       break;
405    case PIPE_FORMAT_Z24_UNORM_S8_UINT:
406    case PIPE_FORMAT_S8_UINT_Z24_UNORM:
407       rb->InternalFormat = GL_DEPTH24_STENCIL8_EXT;
408       break;
409    case PIPE_FORMAT_Z24X8_UNORM:
410    case PIPE_FORMAT_X8Z24_UNORM:
411       rb->InternalFormat = GL_DEPTH_COMPONENT24;
412       break;
413    case PIPE_FORMAT_S8_UINT:
414       rb->InternalFormat = GL_STENCIL_INDEX8_EXT;
415       break;
416    case PIPE_FORMAT_R16G16B16A16_SNORM:
417       /* accum buffer */
418       rb->InternalFormat = GL_RGBA16_SNORM;
419       break;
420    case PIPE_FORMAT_R16G16B16A16_UNORM:
421       rb->InternalFormat = GL_RGBA16;
422       break;
423    case PIPE_FORMAT_R16G16B16_UNORM:
424       rb->InternalFormat = GL_RGB16;
425       break;
426    case PIPE_FORMAT_R8_UNORM:
427       rb->InternalFormat = GL_R8;
428       break;
429    case PIPE_FORMAT_R8G8_UNORM:
430       rb->InternalFormat = GL_RG8;
431       break;
432    case PIPE_FORMAT_R16_UNORM:
433       rb->InternalFormat = GL_R16;
434       break;
435    case PIPE_FORMAT_R16G16_UNORM:
436       rb->InternalFormat = GL_RG16;
437       break;
438    case PIPE_FORMAT_R32G32B32A32_FLOAT:
439       rb->InternalFormat = GL_RGBA32F;
440       break;
441    case PIPE_FORMAT_R32G32B32X32_FLOAT:
442    case PIPE_FORMAT_R32G32B32_FLOAT:
443       rb->InternalFormat = GL_RGB32F;
444       break;
445    case PIPE_FORMAT_R16G16B16A16_FLOAT:
446       rb->InternalFormat = GL_RGBA16F;
447       break;
448    case PIPE_FORMAT_R16G16B16X16_FLOAT:
449       rb->InternalFormat = GL_RGB16F;
450       break;
451    default:
452       _mesa_problem(NULL,
453                     "Unexpected format %s in st_new_renderbuffer_fb",
454                     util_format_name(format));
455       FREE(rb);
456       return NULL;
457    }
458 
459    rb->surface = NULL;
460 
461    return rb;
462 }
463 
464 /**
465  * Add a renderbuffer to the framebuffer.  The framebuffer is one that
466  * corresponds to a window and is not a user-created FBO.
467  */
468 static bool
st_framebuffer_add_renderbuffer(struct gl_framebuffer * stfb,gl_buffer_index idx,bool prefer_srgb)469 st_framebuffer_add_renderbuffer(struct gl_framebuffer *stfb,
470                                 gl_buffer_index idx, bool prefer_srgb)
471 {
472    struct gl_renderbuffer *rb;
473    enum pipe_format format;
474    bool sw;
475 
476    assert(_mesa_is_winsys_fbo(stfb));
477 
478    /* do not distinguish depth/stencil buffers */
479    if (idx == BUFFER_STENCIL)
480       idx = BUFFER_DEPTH;
481 
482    switch (idx) {
483    case BUFFER_DEPTH:
484       format = stfb->drawable->visual->depth_stencil_format;
485       sw = false;
486       break;
487    case BUFFER_ACCUM:
488       format = stfb->drawable->visual->accum_format;
489       sw = true;
490       break;
491    default:
492       format = stfb->drawable->visual->color_format;
493       if (prefer_srgb)
494          format = util_format_srgb(format);
495       sw = false;
496       break;
497    }
498 
499    if (format == PIPE_FORMAT_NONE)
500       return false;
501 
502    rb = st_new_renderbuffer_fb(format, stfb->drawable->visual->samples, sw);
503    if (!rb)
504       return false;
505 
506    if (idx != BUFFER_DEPTH) {
507       _mesa_attach_and_own_rb(stfb, idx, rb);
508       return true;
509    }
510 
511    bool rb_ownership_taken = false;
512    if (util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_ZS, 0)) {
513       _mesa_attach_and_own_rb(stfb, BUFFER_DEPTH, rb);
514       rb_ownership_taken = true;
515    }
516 
517    if (util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_ZS, 1)) {
518       if (rb_ownership_taken)
519          _mesa_attach_and_reference_rb(stfb, BUFFER_STENCIL, rb);
520       else
521          _mesa_attach_and_own_rb(stfb, BUFFER_STENCIL, rb);
522    }
523 
524    return true;
525 }
526 
527 
528 /**
529  * Intialize a struct gl_config from a visual.
530  */
531 static void
st_visual_to_context_mode(const struct st_visual * visual,struct gl_config * mode)532 st_visual_to_context_mode(const struct st_visual *visual,
533                           struct gl_config *mode)
534 {
535    memset(mode, 0, sizeof(*mode));
536 
537    if (st_visual_have_buffers(visual, ST_ATTACHMENT_BACK_LEFT_MASK))
538       mode->doubleBufferMode = GL_TRUE;
539 
540    if (st_visual_have_buffers(visual,
541             ST_ATTACHMENT_FRONT_RIGHT_MASK | ST_ATTACHMENT_BACK_RIGHT_MASK))
542       mode->stereoMode = GL_TRUE;
543 
544    if (visual->color_format != PIPE_FORMAT_NONE) {
545       mode->redBits =
546          util_format_get_component_bits(visual->color_format,
547                UTIL_FORMAT_COLORSPACE_RGB, 0);
548       mode->greenBits =
549          util_format_get_component_bits(visual->color_format,
550                UTIL_FORMAT_COLORSPACE_RGB, 1);
551       mode->blueBits =
552          util_format_get_component_bits(visual->color_format,
553                UTIL_FORMAT_COLORSPACE_RGB, 2);
554       mode->alphaBits =
555          util_format_get_component_bits(visual->color_format,
556                UTIL_FORMAT_COLORSPACE_RGB, 3);
557 
558       mode->rgbBits = mode->redBits +
559          mode->greenBits + mode->blueBits + mode->alphaBits;
560       mode->sRGBCapable = util_format_is_srgb(visual->color_format);
561       mode->floatMode = util_format_is_float(visual->color_format);
562    }
563 
564    if (visual->depth_stencil_format != PIPE_FORMAT_NONE) {
565       mode->depthBits =
566          util_format_get_component_bits(visual->depth_stencil_format,
567                UTIL_FORMAT_COLORSPACE_ZS, 0);
568       mode->stencilBits =
569          util_format_get_component_bits(visual->depth_stencil_format,
570                UTIL_FORMAT_COLORSPACE_ZS, 1);
571    }
572 
573    if (visual->accum_format != PIPE_FORMAT_NONE) {
574       mode->accumRedBits =
575          util_format_get_component_bits(visual->accum_format,
576                UTIL_FORMAT_COLORSPACE_RGB, 0);
577       mode->accumGreenBits =
578          util_format_get_component_bits(visual->accum_format,
579                UTIL_FORMAT_COLORSPACE_RGB, 1);
580       mode->accumBlueBits =
581          util_format_get_component_bits(visual->accum_format,
582                UTIL_FORMAT_COLORSPACE_RGB, 2);
583       mode->accumAlphaBits =
584          util_format_get_component_bits(visual->accum_format,
585                UTIL_FORMAT_COLORSPACE_RGB, 3);
586    }
587 
588    if (visual->samples > 1) {
589       mode->samples = visual->samples;
590    }
591 }
592 
593 
594 /**
595  * Create a framebuffer from a manager interface.
596  */
597 static struct gl_framebuffer *
st_framebuffer_create(struct st_context * st,struct pipe_frontend_drawable * drawable)598 st_framebuffer_create(struct st_context *st,
599                       struct pipe_frontend_drawable *drawable)
600 {
601    struct gl_framebuffer *stfb;
602    struct gl_config mode;
603    gl_buffer_index idx;
604    bool prefer_srgb = false;
605 
606    if (!drawable)
607       return NULL;
608 
609    stfb = CALLOC_STRUCT(gl_framebuffer);
610    if (!stfb)
611       return NULL;
612 
613    st_visual_to_context_mode(drawable->visual, &mode);
614 
615    /*
616     * For desktop GL, sRGB framebuffer write is controlled by both the
617     * capability of the framebuffer and GL_FRAMEBUFFER_SRGB.  We should
618     * advertise the capability when the pipe driver (and core Mesa) supports
619     * it so that applications can enable sRGB write when they want to.
620     *
621     * This is not to be confused with GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB.  When
622     * the attribute is GLX_TRUE, it tells the st manager to pick a color
623     * format such that util_format_srgb(visual->color_format) can be supported
624     * by the pipe driver.  We still need to advertise the capability here.
625     *
626     * For GLES, however, sRGB framebuffer write is initially only controlled
627     * by the capability of the framebuffer, with GL_EXT_sRGB_write_control
628     * control is given back to the applications, but GL_FRAMEBUFFER_SRGB is
629     * still enabled by default since this is the behaviour when
630     * EXT_sRGB_write_control is not available. Since GL_EXT_sRGB_write_control
631     * brings GLES on par with desktop GLs EXT_framebuffer_sRGB, in mesa this
632     * is also expressed by using the same extension flag
633     */
634    if (_mesa_has_EXT_framebuffer_sRGB(st->ctx)) {
635       struct pipe_screen *screen = st->screen;
636       const enum pipe_format srgb_format =
637          util_format_srgb(drawable->visual->color_format);
638 
639       if (srgb_format != PIPE_FORMAT_NONE &&
640           st_pipe_format_to_mesa_format(srgb_format) != MESA_FORMAT_NONE &&
641           screen->is_format_supported(screen, srgb_format,
642                                       PIPE_TEXTURE_2D, drawable->visual->samples,
643                                       drawable->visual->samples,
644                                       (PIPE_BIND_DISPLAY_TARGET |
645                                        PIPE_BIND_RENDER_TARGET))) {
646          mode.sRGBCapable = GL_TRUE;
647          /* Since GL_FRAMEBUFFER_SRGB is enabled by default on GLES we must not
648           * create renderbuffers with an sRGB format derived from the
649           * visual->color_format, but we still want sRGB for desktop GL.
650           */
651          prefer_srgb = _mesa_is_desktop_gl(st->ctx);
652       }
653    }
654 
655    _mesa_initialize_window_framebuffer(stfb, &mode);
656 
657    stfb->drawable = drawable;
658    stfb->drawable_ID = drawable->ID;
659    stfb->drawable_stamp = p_atomic_read(&drawable->stamp) - 1;
660 
661    /* add the color buffer */
662    idx = stfb->_ColorDrawBufferIndexes[0];
663    if (!st_framebuffer_add_renderbuffer(stfb, idx, prefer_srgb)) {
664       FREE(stfb);
665       return NULL;
666    }
667 
668    st_framebuffer_add_renderbuffer(stfb, BUFFER_DEPTH, false);
669    st_framebuffer_add_renderbuffer(stfb, BUFFER_ACCUM, false);
670 
671    stfb->stamp = 0;
672    st_framebuffer_update_attachments(stfb);
673 
674    return stfb;
675 }
676 
677 
678 static uint32_t
drawable_hash(const void * key)679 drawable_hash(const void *key)
680 {
681    return (uintptr_t)key;
682 }
683 
684 
685 static bool
drawable_equal(const void * a,const void * b)686 drawable_equal(const void *a, const void *b)
687 {
688    return (struct pipe_frontend_drawable *)a == (struct pipe_frontend_drawable *)b;
689 }
690 
691 
692 static bool
drawable_lookup(struct pipe_frontend_screen * fscreen,const struct pipe_frontend_drawable * drawable)693 drawable_lookup(struct pipe_frontend_screen *fscreen,
694                 const struct pipe_frontend_drawable *drawable)
695 {
696    struct st_screen *screen =
697       (struct st_screen *)fscreen->st_screen;
698    struct hash_entry *entry;
699 
700    assert(screen);
701    assert(screen->drawable_ht);
702 
703    simple_mtx_lock(&screen->st_mutex);
704    entry = _mesa_hash_table_search(screen->drawable_ht, drawable);
705    simple_mtx_unlock(&screen->st_mutex);
706 
707    return entry != NULL;
708 }
709 
710 
711 static bool
drawable_insert(struct pipe_frontend_screen * fscreen,struct pipe_frontend_drawable * drawable)712 drawable_insert(struct pipe_frontend_screen *fscreen,
713                 struct pipe_frontend_drawable *drawable)
714 {
715    struct st_screen *screen =
716       (struct st_screen *)fscreen->st_screen;
717    struct hash_entry *entry;
718 
719    assert(screen);
720    assert(screen->drawable_ht);
721 
722    simple_mtx_lock(&screen->st_mutex);
723    entry = _mesa_hash_table_insert(screen->drawable_ht, drawable, drawable);
724    simple_mtx_unlock(&screen->st_mutex);
725 
726    return entry != NULL;
727 }
728 
729 
730 static void
drawable_remove(struct pipe_frontend_screen * fscreen,struct pipe_frontend_drawable * drawable)731 drawable_remove(struct pipe_frontend_screen *fscreen,
732                 struct pipe_frontend_drawable *drawable)
733 {
734    struct st_screen *screen =
735       (struct st_screen *)fscreen->st_screen;
736    struct hash_entry *entry;
737 
738    if (!screen || !screen->drawable_ht)
739       return;
740 
741    simple_mtx_lock(&screen->st_mutex);
742    entry = _mesa_hash_table_search(screen->drawable_ht, drawable);
743    if (!entry)
744       goto unlock;
745 
746    _mesa_hash_table_remove(screen->drawable_ht, entry);
747 
748 unlock:
749    simple_mtx_unlock(&screen->st_mutex);
750 }
751 
752 
753 /**
754  * The framebuffer interface object is no longer valid.
755  * Remove the object from the framebuffer interface hash table.
756  */
757 void
st_api_destroy_drawable(struct pipe_frontend_drawable * drawable)758 st_api_destroy_drawable(struct pipe_frontend_drawable *drawable)
759 {
760    if (!drawable)
761       return;
762 
763    drawable_remove(drawable->fscreen, drawable);
764 }
765 
766 
767 /**
768  * Purge the winsys buffers list to remove any references to
769  * non-existing framebuffer interface objects.
770  */
771 static void
st_framebuffers_purge(struct st_context * st)772 st_framebuffers_purge(struct st_context *st)
773 {
774    struct pipe_frontend_screen *fscreen = st->frontend_screen;
775    struct gl_framebuffer *stfb, *next;
776 
777    assert(fscreen);
778 
779    LIST_FOR_EACH_ENTRY_SAFE_REV(stfb, next, &st->winsys_buffers, head) {
780       struct pipe_frontend_drawable *drawable = stfb->drawable;
781 
782       assert(drawable);
783 
784       /**
785        * If the corresponding framebuffer interface object no longer exists,
786        * remove the framebuffer object from the context's winsys buffers list,
787        * and unreference the framebuffer object, so its resources can be
788        * deleted.
789        */
790       if (!drawable_lookup(fscreen, drawable)) {
791          list_del(&stfb->head);
792          _mesa_reference_framebuffer(&stfb, NULL);
793       }
794    }
795 }
796 
797 
798 void
st_context_flush(struct st_context * st,unsigned flags,struct pipe_fence_handle ** fence,void (* before_flush_cb)(void *),void * args)799 st_context_flush(struct st_context *st, unsigned flags,
800                  struct pipe_fence_handle **fence,
801                  void (*before_flush_cb) (void*), void* args)
802 {
803    unsigned pipe_flags = 0;
804 
805    MESA_TRACE_FUNC();
806 
807    if (flags & ST_FLUSH_END_OF_FRAME)
808       pipe_flags |= PIPE_FLUSH_END_OF_FRAME;
809    if (flags & ST_FLUSH_FENCE_FD)
810       pipe_flags |= PIPE_FLUSH_FENCE_FD;
811 
812    /* We can do these in any order because FLUSH_VERTICES will also flush
813     * the bitmap cache if there are any unflushed vertices.
814     */
815    st_flush_bitmap_cache(st);
816    FLUSH_VERTICES(st->ctx, 0, 0);
817 
818    /* Notify the caller that we're ready to flush */
819    if (before_flush_cb)
820       before_flush_cb(args);
821    st_flush(st, fence, pipe_flags);
822 
823    if ((flags & ST_FLUSH_WAIT) && fence && *fence) {
824       st->screen->fence_finish(st->screen, NULL, *fence,
825                                      OS_TIMEOUT_INFINITE);
826       st->screen->fence_reference(st->screen, fence, NULL);
827    }
828 
829    if (flags & ST_FLUSH_FRONT)
830       st_manager_flush_frontbuffer(st);
831 }
832 
833 /**
834  * Replace the texture image of a texture object at the specified level.
835  *
836  * This is only for GLX_EXT_texture_from_pixmap and equivalent features
837  * in EGL and WGL.
838  */
839 bool
st_context_teximage(struct st_context * st,GLenum target,int level,enum pipe_format pipe_format,struct pipe_resource * tex,bool mipmap)840 st_context_teximage(struct st_context *st, GLenum target,
841                     int level, enum pipe_format pipe_format,
842                     struct pipe_resource *tex, bool mipmap)
843 {
844    struct gl_context *ctx = st->ctx;
845    struct gl_texture_object *texObj;
846    struct gl_texture_image *texImage;
847    GLenum internalFormat;
848    GLuint width, height, depth;
849 
850    texObj = _mesa_get_current_tex_object(ctx, target);
851 
852    _mesa_lock_texture(ctx, texObj);
853 
854    /* switch to surface based */
855    if (!texObj->surface_based) {
856       _mesa_clear_texture_object(ctx, texObj, NULL);
857       texObj->surface_based = GL_TRUE;
858    }
859 
860    texImage = _mesa_get_tex_image(ctx, texObj, target, level);
861    if (tex) {
862       mesa_format texFormat = st_pipe_format_to_mesa_format(pipe_format);
863 
864       if (util_format_has_alpha(tex->format))
865          internalFormat = GL_RGBA;
866       else
867          internalFormat = GL_RGB;
868 
869       _mesa_init_teximage_fields(ctx, texImage,
870                                  tex->width0, tex->height0, 1, 0,
871                                  internalFormat, texFormat);
872 
873       width = tex->width0;
874       height = tex->height0;
875       depth = tex->depth0;
876 
877       /* grow the image size until we hit level = 0 */
878       while (level > 0) {
879          if (width != 1)
880             width <<= 1;
881          if (height != 1)
882             height <<= 1;
883          if (depth != 1)
884             depth <<= 1;
885          level--;
886       }
887    }
888    else {
889       _mesa_clear_texture_image(ctx, texImage);
890       width = height = depth = 0;
891    }
892    _mesa_update_texture_object_swizzle(ctx, texObj);
893 
894    pipe_resource_reference(&texObj->pt, tex);
895    st_texture_release_all_sampler_views(st, texObj);
896    pipe_resource_reference(&texImage->pt, tex);
897    texObj->surface_format = pipe_format;
898 
899    texObj->needs_validation = true;
900 
901    _mesa_dirty_texobj(ctx, texObj);
902    ctx->Shared->HasExternallySharedImages = true;
903    _mesa_unlock_texture(ctx, texObj);
904 
905    return true;
906 }
907 
908 
909 /**
910  * Invalidate states to notify the frontend that driver states have been
911  * changed behind its back.
912  */
913 void
st_context_invalidate_state(struct st_context * st,unsigned flags)914 st_context_invalidate_state(struct st_context *st, unsigned flags)
915 {
916    struct gl_context *ctx = st->ctx;
917 
918    if (flags & ST_INVALIDATE_FS_SAMPLER_VIEWS)
919       ctx->NewDriverState |= ST_NEW_FS_SAMPLER_VIEWS;
920    if (flags & ST_INVALIDATE_FS_CONSTBUF0)
921       ctx->NewDriverState |= ST_NEW_FS_CONSTANTS;
922    if (flags & ST_INVALIDATE_VS_CONSTBUF0)
923       ctx->NewDriverState |= ST_NEW_VS_CONSTANTS;
924    if (flags & ST_INVALIDATE_VERTEX_BUFFERS) {
925       ctx->Array.NewVertexElements = true;
926       ctx->NewDriverState |= ST_NEW_VERTEX_ARRAYS;
927    }
928    if (flags & ST_INVALIDATE_FB_STATE)
929       ctx->NewDriverState |= ST_NEW_FB_STATE;
930 }
931 
932 
933 void
st_screen_destroy(struct pipe_frontend_screen * fscreen)934 st_screen_destroy(struct pipe_frontend_screen *fscreen)
935 {
936    struct st_screen *screen = fscreen->st_screen;
937 
938    if (screen && screen->drawable_ht) {
939       _mesa_hash_table_destroy(screen->drawable_ht, NULL);
940       simple_mtx_destroy(&screen->st_mutex);
941       FREE(screen);
942       fscreen->st_screen = NULL;
943    }
944 }
945 
946 
947 /**
948  * Create a rendering context.
949  */
950 struct st_context *
st_api_create_context(struct pipe_frontend_screen * fscreen,const struct st_context_attribs * attribs,enum st_context_error * error,struct st_context * shared_ctx)951 st_api_create_context(struct pipe_frontend_screen *fscreen,
952                       const struct st_context_attribs *attribs,
953                       enum st_context_error *error,
954                       struct st_context *shared_ctx)
955 {
956    struct st_context *st;
957    struct pipe_context *pipe;
958    struct gl_config mode, *mode_ptr = &mode;
959    bool no_error = false;
960 
961    _mesa_initialize(attribs->options.mesa_extension_override);
962 
963    /* Create a hash table for the framebuffer interface objects
964     * if it has not been created for this st manager.
965     */
966    if (fscreen->st_screen == NULL) {
967       struct st_screen *screen;
968 
969       screen = CALLOC_STRUCT(st_screen);
970       simple_mtx_init(&screen->st_mutex, mtx_plain);
971       screen->drawable_ht = _mesa_hash_table_create(NULL,
972                                                  drawable_hash,
973                                                  drawable_equal);
974       fscreen->st_screen = screen;
975    }
976 
977    if (attribs->flags & ST_CONTEXT_FLAG_NO_ERROR)
978       no_error = true;
979 
980    /* OpenGL ES 2.0+ does not support sampler state LOD bias. If we are creating
981     * a GLES context, communicate that to the the driver to allow optimization.
982     */
983    bool is_gles = attribs->profile == API_OPENGLES2;
984    unsigned lod_bias_flag = is_gles ? PIPE_CONTEXT_NO_LOD_BIAS : 0;
985 
986    pipe = fscreen->screen->context_create(fscreen->screen, NULL,
987                                           PIPE_CONTEXT_PREFER_THREADED |
988                                           lod_bias_flag |
989                                           attribs->context_flags);
990    if (!pipe) {
991       *error = ST_CONTEXT_ERROR_NO_MEMORY;
992       return NULL;
993    }
994 
995    st_visual_to_context_mode(&attribs->visual, &mode);
996    if (attribs->visual.color_format == PIPE_FORMAT_NONE)
997       mode_ptr = NULL;
998    st = st_create_context(attribs->profile, pipe, mode_ptr, shared_ctx,
999                           &attribs->options, no_error,
1000                           !!fscreen->validate_egl_image);
1001    if (!st) {
1002       *error = ST_CONTEXT_ERROR_NO_MEMORY;
1003       pipe->destroy(pipe);
1004       return NULL;
1005    }
1006 
1007    if (attribs->flags & ST_CONTEXT_FLAG_DEBUG) {
1008       if (!_mesa_set_debug_state_int(st->ctx, GL_DEBUG_OUTPUT, GL_TRUE)) {
1009          *error = ST_CONTEXT_ERROR_NO_MEMORY;
1010          return NULL;
1011       }
1012 
1013       st->ctx->Const.ContextFlags |= GL_CONTEXT_FLAG_DEBUG_BIT;
1014    }
1015 
1016    if (st->ctx->Const.ContextFlags & GL_CONTEXT_FLAG_DEBUG_BIT) {
1017       _mesa_update_debug_callback(st->ctx);
1018    }
1019 
1020    if (attribs->flags & ST_CONTEXT_FLAG_FORWARD_COMPATIBLE)
1021       st->ctx->Const.ContextFlags |= GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT;
1022 
1023    if (attribs->context_flags & PIPE_CONTEXT_ROBUST_BUFFER_ACCESS) {
1024       st->ctx->Const.ContextFlags |= GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB;
1025       st->ctx->Const.RobustAccess = GL_TRUE;
1026    }
1027 
1028    if (attribs->context_flags & PIPE_CONTEXT_LOSE_CONTEXT_ON_RESET) {
1029       st->ctx->Const.ResetStrategy = GL_LOSE_CONTEXT_ON_RESET_ARB;
1030       st_install_device_reset_callback(st);
1031    }
1032 
1033    if (attribs->flags & ST_CONTEXT_FLAG_RELEASE_NONE)
1034        st->ctx->Const.ContextReleaseBehavior = GL_NONE;
1035 
1036    /* need to perform version check */
1037    if (attribs->major > 1 || attribs->minor > 0) {
1038       /* Is the actual version less than the requested version?
1039        */
1040       if (st->ctx->Version < attribs->major * 10U + attribs->minor) {
1041          *error = ST_CONTEXT_ERROR_BAD_VERSION;
1042          st_destroy_context(st);
1043          return NULL;
1044       }
1045    }
1046 
1047    st->can_scissor_clear = !!st->screen->get_param(st->screen, PIPE_CAP_CLEAR_SCISSORED);
1048 
1049    st->ctx->invalidate_on_gl_viewport =
1050       fscreen->get_param(fscreen, ST_MANAGER_BROKEN_INVALIDATE);
1051 
1052    st->frontend_screen = fscreen;
1053 
1054    if (st->ctx->IntelBlackholeRender &&
1055        st->screen->get_param(st->screen, PIPE_CAP_FRONTEND_NOOP))
1056       st->pipe->set_frontend_noop(st->pipe, st->ctx->IntelBlackholeRender);
1057 
1058    *error = ST_CONTEXT_SUCCESS;
1059    return st;
1060 }
1061 
1062 
1063 /**
1064  * Get the currently bound context in the calling thread.
1065  */
1066 struct st_context *
st_api_get_current(void)1067 st_api_get_current(void)
1068 {
1069    GET_CURRENT_CONTEXT(ctx);
1070 
1071    return ctx ? ctx->st : NULL;
1072 }
1073 
1074 
1075 static struct gl_framebuffer *
st_framebuffer_reuse_or_create(struct st_context * st,struct pipe_frontend_drawable * drawable)1076 st_framebuffer_reuse_or_create(struct st_context *st,
1077                                struct pipe_frontend_drawable *drawable)
1078 {
1079    struct gl_framebuffer *cur = NULL, *stfb = NULL;
1080 
1081    if (!drawable)
1082       return NULL;
1083 
1084    /* Check if there is already a framebuffer object for the specified
1085     * framebuffer interface in this context. If there is one, use it.
1086     */
1087    LIST_FOR_EACH_ENTRY(cur, &st->winsys_buffers, head) {
1088       if (cur->drawable_ID == drawable->ID) {
1089          _mesa_reference_framebuffer(&stfb, cur);
1090          break;
1091       }
1092    }
1093 
1094    /* If there is not already a framebuffer object, create one */
1095    if (stfb == NULL) {
1096       cur = st_framebuffer_create(st, drawable);
1097 
1098       if (cur) {
1099          /* add the referenced framebuffer interface object to
1100           * the framebuffer interface object hash table.
1101           */
1102          if (!drawable_insert(drawable->fscreen, drawable)) {
1103             _mesa_reference_framebuffer(&cur, NULL);
1104             return NULL;
1105          }
1106 
1107          /* add to the context's winsys buffers list */
1108          list_add(&cur->head, &st->winsys_buffers);
1109 
1110          _mesa_reference_framebuffer(&stfb, cur);
1111       }
1112    }
1113 
1114    return stfb;
1115 }
1116 
1117 
1118 /**
1119  * Bind the context to the calling thread with draw and read as drawables.
1120  *
1121  * The framebuffers might be NULL, meaning the context is surfaceless.
1122  */
1123 bool
st_api_make_current(struct st_context * st,struct pipe_frontend_drawable * stdrawi,struct pipe_frontend_drawable * streadi)1124 st_api_make_current(struct st_context *st,
1125                     struct pipe_frontend_drawable *stdrawi,
1126                     struct pipe_frontend_drawable *streadi)
1127 {
1128    struct gl_framebuffer *stdraw, *stread;
1129    bool ret;
1130 
1131    if (st) {
1132       /* reuse or create the draw fb */
1133       stdraw = st_framebuffer_reuse_or_create(st, stdrawi);
1134       if (streadi != stdrawi) {
1135          /* do the same for the read fb */
1136          stread = st_framebuffer_reuse_or_create(st, streadi);
1137       }
1138       else {
1139          stread = NULL;
1140          /* reuse the draw fb for the read fb */
1141          if (stdraw)
1142             _mesa_reference_framebuffer(&stread, stdraw);
1143       }
1144 
1145       /* If framebuffers were asked for, we'd better have allocated them */
1146       if ((stdrawi && !stdraw) || (streadi && !stread))
1147          return false;
1148 
1149       if (stdraw && stread) {
1150          st_framebuffer_validate(stdraw, st);
1151          if (stread != stdraw)
1152             st_framebuffer_validate(stread, st);
1153 
1154          ret = _mesa_make_current(st->ctx, stdraw, stread);
1155 
1156          st->draw_stamp = stdraw->stamp - 1;
1157          st->read_stamp = stread->stamp - 1;
1158          st_context_validate(st, stdraw, stread);
1159       }
1160       else {
1161          struct gl_framebuffer *incomplete = _mesa_get_incomplete_framebuffer();
1162          ret = _mesa_make_current(st->ctx, incomplete, incomplete);
1163       }
1164 
1165       _mesa_reference_framebuffer(&stdraw, NULL);
1166       _mesa_reference_framebuffer(&stread, NULL);
1167 
1168       /* Purge the context's winsys_buffers list in case any
1169        * of the referenced drawables no longer exist.
1170        */
1171       st_framebuffers_purge(st);
1172    }
1173    else {
1174       GET_CURRENT_CONTEXT(ctx);
1175 
1176       if (ctx) {
1177          /* Before releasing the context, release its associated
1178           * winsys buffers first. Then purge the context's winsys buffers list
1179           * to free the resources of any winsys buffers that no longer have
1180           * an existing drawable.
1181           */
1182          ret = _mesa_make_current(ctx, NULL, NULL);
1183          st_framebuffers_purge(ctx->st);
1184       }
1185 
1186       ret = _mesa_make_current(NULL, NULL, NULL);
1187    }
1188 
1189    return ret;
1190 }
1191 
1192 
1193 /**
1194  * Flush the front buffer if the current context renders to the front buffer.
1195  */
1196 void
st_manager_flush_frontbuffer(struct st_context * st)1197 st_manager_flush_frontbuffer(struct st_context *st)
1198 {
1199    struct gl_framebuffer *stfb = st_ws_framebuffer(st->ctx->DrawBuffer);
1200    struct gl_renderbuffer *rb = NULL;
1201 
1202    if (!stfb)
1203       return;
1204 
1205    /* If the context uses a doublebuffered visual, but the buffer is
1206     * single-buffered, guess that it's a pbuffer, which doesn't need
1207     * flushing.
1208     */
1209    if (st->ctx->Visual.doubleBufferMode &&
1210        !stfb->Visual.doubleBufferMode)
1211       return;
1212 
1213    /* Check front buffer used at the GL API level. */
1214    enum st_attachment_type statt = ST_ATTACHMENT_FRONT_LEFT;
1215    rb = stfb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer;
1216    if (!rb) {
1217        /* Check back buffer redirected by EGL_KHR_mutable_render_buffer. */
1218        statt = ST_ATTACHMENT_BACK_LEFT;
1219        rb = stfb->Attachment[BUFFER_BACK_LEFT].Renderbuffer;
1220    }
1221 
1222    /* Do we have a front color buffer and has it been drawn to since last
1223     * frontbuffer flush?
1224     */
1225    if (rb && rb->defined &&
1226        stfb->drawable->flush_front(st, stfb->drawable, statt)) {
1227       rb->defined = GL_FALSE;
1228 
1229       /* Trigger an update of rb->defined on next draw */
1230       st->ctx->NewDriverState |= ST_NEW_FB_STATE;
1231    }
1232 }
1233 
1234 
1235 /**
1236  * Re-validate the framebuffers.
1237  */
1238 void
st_manager_validate_framebuffers(struct st_context * st)1239 st_manager_validate_framebuffers(struct st_context *st)
1240 {
1241    struct gl_framebuffer *stdraw = st_ws_framebuffer(st->ctx->DrawBuffer);
1242    struct gl_framebuffer *stread = st_ws_framebuffer(st->ctx->ReadBuffer);
1243 
1244    if (stdraw)
1245       st_framebuffer_validate(stdraw, st);
1246    if (stread && stread != stdraw)
1247       st_framebuffer_validate(stread, st);
1248 
1249    st_context_validate(st, stdraw, stread);
1250 }
1251 
1252 
1253 /**
1254  * Flush any outstanding swapbuffers on the current draw framebuffer.
1255  */
1256 void
st_manager_flush_swapbuffers(void)1257 st_manager_flush_swapbuffers(void)
1258 {
1259    GET_CURRENT_CONTEXT(ctx);
1260    struct st_context *st = (ctx) ? ctx->st : NULL;
1261    struct gl_framebuffer *stfb;
1262 
1263    if (!st)
1264       return;
1265 
1266    stfb = st_ws_framebuffer(ctx->DrawBuffer);
1267    if (!stfb || !stfb->drawable->flush_swapbuffers)
1268       return;
1269 
1270    stfb->drawable->flush_swapbuffers(st, stfb->drawable);
1271 }
1272 
1273 
1274 /**
1275  * Add a color renderbuffer on demand.  The FBO must correspond to a window,
1276  * not a user-created FBO.
1277  */
1278 bool
st_manager_add_color_renderbuffer(struct gl_context * ctx,struct gl_framebuffer * fb,gl_buffer_index idx)1279 st_manager_add_color_renderbuffer(struct gl_context *ctx,
1280                                   struct gl_framebuffer *fb,
1281                                   gl_buffer_index idx)
1282 {
1283    struct gl_framebuffer *stfb = st_ws_framebuffer(fb);
1284 
1285    /* FBO */
1286    if (!stfb)
1287       return false;
1288 
1289    assert(_mesa_is_winsys_fbo(fb));
1290 
1291    if (stfb->Attachment[idx].Renderbuffer)
1292       return true;
1293 
1294    switch (idx) {
1295    case BUFFER_FRONT_LEFT:
1296    case BUFFER_BACK_LEFT:
1297    case BUFFER_FRONT_RIGHT:
1298    case BUFFER_BACK_RIGHT:
1299       break;
1300    default:
1301       return false;
1302    }
1303 
1304    if (!st_framebuffer_add_renderbuffer(stfb, idx,
1305                                         stfb->Visual.sRGBCapable))
1306       return false;
1307 
1308    st_framebuffer_update_attachments(stfb);
1309 
1310    /*
1311     * Force a call to the frontend manager to validate the
1312     * new renderbuffer. It might be that there is a window system
1313     * renderbuffer available.
1314     */
1315    if (stfb->drawable)
1316       stfb->drawable_stamp = p_atomic_read(&stfb->drawable->stamp) - 1;
1317 
1318    st_invalidate_buffers(st_context(ctx));
1319 
1320    return true;
1321 }
1322 
1323 
1324 static unsigned
get_version(struct pipe_screen * screen,struct st_config_options * options,gl_api api)1325 get_version(struct pipe_screen *screen,
1326             struct st_config_options *options, gl_api api)
1327 {
1328    struct gl_constants consts = {0};
1329    struct gl_extensions extensions = {0};
1330    GLuint version;
1331 
1332    if (_mesa_override_gl_version_contextless(&consts, &api, &version)) {
1333       return version;
1334    }
1335 
1336    _mesa_init_constants(&consts, api);
1337    _mesa_init_extensions(&extensions);
1338 
1339    st_init_limits(screen, &consts, &extensions, api);
1340    st_init_extensions(screen, &consts, &extensions, options, api);
1341    version = _mesa_get_version(&extensions, &consts, api);
1342    free(consts.SpirVExtensions);
1343    return version;
1344 }
1345 
1346 
1347 /**
1348  * Query supported OpenGL versions. (if applicable)
1349  * The format is (major*10+minor).
1350  */
1351 void
st_api_query_versions(struct pipe_frontend_screen * fscreen,struct st_config_options * options,int * gl_core_version,int * gl_compat_version,int * gl_es1_version,int * gl_es2_version)1352 st_api_query_versions(struct pipe_frontend_screen *fscreen,
1353                       struct st_config_options *options,
1354                       int *gl_core_version,
1355                       int *gl_compat_version,
1356                       int *gl_es1_version,
1357                       int *gl_es2_version)
1358 {
1359    *gl_core_version = get_version(fscreen->screen, options, API_OPENGL_CORE);
1360    *gl_compat_version = get_version(fscreen->screen, options, API_OPENGL_COMPAT);
1361    *gl_es1_version = get_version(fscreen->screen, options, API_OPENGLES);
1362    *gl_es2_version = get_version(fscreen->screen, options, API_OPENGLES2);
1363 }
1364 
1365 
1366 void
st_manager_invalidate_drawables(struct gl_context * ctx)1367 st_manager_invalidate_drawables(struct gl_context *ctx)
1368 {
1369    struct gl_framebuffer *stdraw;
1370    struct gl_framebuffer *stread;
1371 
1372    /*
1373     * Normally we'd want the frontend manager to mark the drawables
1374     * invalid only when needed. This will force the frontend manager
1375     * to revalidate the drawable, rather than just update the context with
1376     * the latest cached drawable info.
1377     */
1378 
1379    stdraw = st_ws_framebuffer(ctx->DrawBuffer);
1380    stread = st_ws_framebuffer(ctx->ReadBuffer);
1381 
1382    if (stdraw)
1383       stdraw->drawable_stamp = p_atomic_read(&stdraw->drawable->stamp) - 1;
1384    if (stread && stread != stdraw)
1385       stread->drawable_stamp = p_atomic_read(&stread->drawable->stamp) - 1;
1386 }
1387