• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
17  * OR 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
20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22  * OTHER DEALINGS IN THE SOFTWARE.
23  *
24  * Authors:
25  *    Chia-I Wu <olv@lunarg.com>
26  */
27 
28 #include "util/u_memory.h"
29 #include "util/u_inlines.h"
30 #include "util/u_atomic.h"
31 #include "state_tracker/st_gl_api.h" /* for st_gl_api_create */
32 #include "pipe/p_state.h"
33 
34 #include "stw_st.h"
35 #include "stw_device.h"
36 #include "stw_framebuffer.h"
37 #include "stw_pixelformat.h"
38 #include "stw_winsys.h"
39 
40 struct stw_st_framebuffer {
41    struct st_framebuffer_iface base;
42 
43    struct stw_framebuffer *fb;
44    struct st_visual stvis;
45 
46    struct pipe_resource *textures[ST_ATTACHMENT_COUNT];
47    struct pipe_resource *msaa_textures[ST_ATTACHMENT_COUNT];
48    struct pipe_resource *back_texture;
49    bool needs_fake_front;
50    unsigned texture_width, texture_height;
51    unsigned texture_mask;
52 };
53 
54 static uint32_t stwfb_ID = 0;
55 
56 /**
57  * Is the given mutex held by the calling thread?
58  */
59 bool
stw_own_mutex(const CRITICAL_SECTION * cs)60 stw_own_mutex(const CRITICAL_SECTION *cs)
61 {
62    // We can't compare OwningThread with our thread handle/id (see
63    // http://stackoverflow.com/a/12675635 ) but we can compare with the
64    // OwningThread member of a critical section we know we own.
65    CRITICAL_SECTION dummy;
66    InitializeCriticalSection(&dummy);
67    EnterCriticalSection(&dummy);
68    if (0)
69       _debug_printf("%p %p\n", cs->OwningThread, dummy.OwningThread);
70    bool ret = cs->OwningThread == dummy.OwningThread;
71    LeaveCriticalSection(&dummy);
72    DeleteCriticalSection(&dummy);
73    return ret;
74 }
75 
76 static void
stw_pipe_blit(struct pipe_context * pipe,struct pipe_resource * dst,struct pipe_resource * src)77 stw_pipe_blit(struct pipe_context *pipe,
78               struct pipe_resource *dst,
79               struct pipe_resource *src)
80 {
81    struct pipe_blit_info blit;
82 
83    if (!dst || !src)
84       return;
85 
86    /* From the GL spec, version 4.2, section 4.1.11 (Additional Multisample
87     *  Fragment Operations):
88     *
89     *      If a framebuffer object is not bound, after all operations have
90     *      been completed on the multisample buffer, the sample values for
91     *      each color in the multisample buffer are combined to produce a
92     *      single color value, and that value is written into the
93     *      corresponding color buffers selected by DrawBuffer or
94     *      DrawBuffers. An implementation may defer the writing of the color
95     *      buffers until a later time, but the state of the framebuffer must
96     *      behave as if the color buffers were updated as each fragment was
97     *      processed. The method of combination is not specified. If the
98     *      framebuffer contains sRGB values, then it is recommended that the
99     *      an average of sample values is computed in a linearized space, as
100     *      for blending (see section 4.1.7).
101     *
102     * In other words, to do a resolve operation in a linear space, we have
103     * to set sRGB formats if the original resources were sRGB, so don't use
104     * util_format_linear.
105     */
106 
107    memset(&blit, 0, sizeof(blit));
108    blit.dst.resource = dst;
109    blit.dst.box.width = dst->width0;
110    blit.dst.box.height = dst->height0;
111    blit.dst.box.depth = 1;
112    blit.dst.format = dst->format;
113    blit.src.resource = src;
114    blit.src.box.width = src->width0;
115    blit.src.box.height = src->height0;
116    blit.src.box.depth = 1;
117    blit.src.format = src->format;
118    blit.mask = PIPE_MASK_RGBA;
119    blit.filter = PIPE_TEX_FILTER_NEAREST;
120 
121    pipe->blit(pipe, &blit);
122 }
123 
124 /**
125  * Remove outdated textures and create the requested ones.
126  */
127 static void
stw_st_framebuffer_validate_locked(struct st_context_iface * stctx,struct st_framebuffer_iface * stfb,unsigned width,unsigned height,unsigned mask)128 stw_st_framebuffer_validate_locked(struct st_context_iface *stctx,
129                                    struct st_framebuffer_iface *stfb,
130                                    unsigned width, unsigned height,
131                                    unsigned mask)
132 {
133    struct stw_st_framebuffer *stwfb = stw_st_framebuffer(stfb);
134    struct pipe_resource templ;
135    unsigned i;
136 
137    memset(&templ, 0, sizeof(templ));
138    templ.target = PIPE_TEXTURE_2D;
139    templ.width0 = width;
140    templ.height0 = height;
141    templ.depth0 = 1;
142    templ.array_size = 1;
143    templ.last_level = 0;
144 
145    /* As of now, the only stw_winsys_framebuffer implementation is
146     * d3d12_wgl_framebuffer and it doesn't support front buffer
147     * drawing. A fake front texture is needed to handle that scenario */
148    if (mask & ST_ATTACHMENT_FRONT_LEFT_MASK &&
149        stwfb->fb->winsys_framebuffer &&
150        stwfb->stvis.samples <= 1) {
151       stwfb->needs_fake_front = true;
152    }
153 
154    /* remove outdated textures */
155    if (stwfb->texture_width != width || stwfb->texture_height != height) {
156       for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
157          pipe_resource_reference(&stwfb->msaa_textures[i], NULL);
158          pipe_resource_reference(&stwfb->textures[i], NULL);
159       }
160       pipe_resource_reference(&stwfb->back_texture, NULL);
161 
162       if (stwfb->fb->winsys_framebuffer) {
163          templ.nr_samples = templ.nr_storage_samples = 1;
164          templ.format = stwfb->stvis.color_format;
165          stwfb->fb->winsys_framebuffer->resize(stwfb->fb->winsys_framebuffer, stctx->pipe, &templ);
166       }
167    }
168 
169    for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
170       enum pipe_format format;
171       unsigned bind;
172 
173       /* the texture already exists or not requested */
174       if (stwfb->textures[i] || !(mask & (1 << i))) {
175          /* remember the texture */
176          if (stwfb->textures[i])
177             mask |= (1 << i);
178          continue;
179       }
180 
181       switch (i) {
182       case ST_ATTACHMENT_FRONT_LEFT:
183       case ST_ATTACHMENT_BACK_LEFT:
184          format = stwfb->stvis.color_format;
185          bind = PIPE_BIND_DISPLAY_TARGET |
186                 PIPE_BIND_SAMPLER_VIEW |
187                 PIPE_BIND_RENDER_TARGET;
188          break;
189       case ST_ATTACHMENT_DEPTH_STENCIL:
190          format = stwfb->stvis.depth_stencil_format;
191          bind = PIPE_BIND_DEPTH_STENCIL;
192          break;
193       default:
194          format = PIPE_FORMAT_NONE;
195          break;
196       }
197 
198       if (format != PIPE_FORMAT_NONE) {
199          templ.format = format;
200 
201          if (bind != PIPE_BIND_DEPTH_STENCIL && stwfb->stvis.samples > 1) {
202             templ.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;
203             templ.nr_samples = templ.nr_storage_samples =
204                stwfb->stvis.samples;
205 
206             stwfb->msaa_textures[i] =
207                stw_dev->screen->resource_create(stw_dev->screen, &templ);
208          }
209 
210          templ.bind = bind;
211          templ.nr_samples = templ.nr_storage_samples = 1;
212          if (stwfb->fb->winsys_framebuffer)
213             stwfb->textures[i] = stwfb->fb->winsys_framebuffer->get_resource(
214                stwfb->fb->winsys_framebuffer, i);
215          else
216             stwfb->textures[i] =
217                stw_dev->screen->resource_create(stw_dev->screen, &templ);
218       }
219    }
220 
221    /* When a fake front buffer is needed for drawing, we use the back buffer
222     * as it reduces the number of blits needed:
223     *
224     *   - When flushing the front buffer, we only need to swap the real buffers
225     *   - When swapping buffers, we can safely overwrite the fake front buffer
226     *     as it is now invalid anyway.
227     *
228     * A new texture is created to store the back buffer content.
229     */
230    if (stwfb->needs_fake_front) {
231       if (!stwfb->back_texture) {
232          templ.format = stwfb->stvis.color_format;
233          templ.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;
234          templ.nr_samples = templ.nr_storage_samples = 1;
235 
236          stwfb->back_texture =
237             stw_dev->screen->resource_create(stw_dev->screen, &templ);
238 
239          /* TODO Only blit if there is something currently drawn on the back buffer */
240          stw_pipe_blit(stctx->pipe,
241                        stwfb->back_texture,
242                        stwfb->textures[ST_ATTACHMENT_BACK_LEFT]);
243       }
244 
245       /* Copying front texture content to fake front texture (back texture) */
246       stw_pipe_blit(stctx->pipe,
247                     stwfb->textures[ST_ATTACHMENT_BACK_LEFT],
248                     stwfb->textures[ST_ATTACHMENT_FRONT_LEFT]);
249    }
250 
251    stwfb->texture_width = width;
252    stwfb->texture_height = height;
253    stwfb->texture_mask = mask;
254 }
255 
256 static bool
stw_st_framebuffer_validate(struct st_context_iface * stctx,struct st_framebuffer_iface * stfb,const enum st_attachment_type * statts,unsigned count,struct pipe_resource ** out)257 stw_st_framebuffer_validate(struct st_context_iface *stctx,
258                             struct st_framebuffer_iface *stfb,
259                             const enum st_attachment_type *statts,
260                             unsigned count,
261                             struct pipe_resource **out)
262 {
263    struct stw_st_framebuffer *stwfb = stw_st_framebuffer(stfb);
264    unsigned statt_mask, i;
265 
266    statt_mask = 0x0;
267    for (i = 0; i < count; i++)
268       statt_mask |= 1 << statts[i];
269 
270    stw_framebuffer_lock(stwfb->fb);
271 
272    if (stwfb->fb->must_resize || stwfb->needs_fake_front || (statt_mask & ~stwfb->texture_mask)) {
273       stw_st_framebuffer_validate_locked(stctx, &stwfb->base,
274             stwfb->fb->width, stwfb->fb->height, statt_mask);
275       stwfb->fb->must_resize = FALSE;
276    }
277 
278    struct pipe_resource **textures =
279       stwfb->stvis.samples > 1 ? stwfb->msaa_textures
280                                : stwfb->textures;
281 
282    for (i = 0; i < count; i++) {
283       struct pipe_resource *texture = NULL;
284 
285       if (stwfb->needs_fake_front) {
286          if (statts[i] == ST_ATTACHMENT_FRONT_LEFT)
287             texture = textures[ST_ATTACHMENT_BACK_LEFT]; /* Fake front buffer */
288          else if (statts[i] == ST_ATTACHMENT_BACK_LEFT)
289             texture = stwfb->back_texture;
290       } else {
291          texture = textures[statts[i]];
292       }
293       pipe_resource_reference(&out[i], texture);
294    }
295 
296    stw_framebuffer_unlock(stwfb->fb);
297 
298    return true;
299 }
300 
301 struct notify_before_flush_cb_args {
302    struct st_context_iface *stctx;
303    struct stw_st_framebuffer *stwfb;
304    unsigned flags;
305 };
306 
307 static void
notify_before_flush_cb(void * _args)308 notify_before_flush_cb(void* _args)
309 {
310    struct notify_before_flush_cb_args *args = (struct notify_before_flush_cb_args *) _args;
311    struct st_context_iface *st = args->stctx;
312    struct pipe_context *pipe = st->pipe;
313 
314    if (args->stwfb->stvis.samples > 1) {
315       /* Resolve the MSAA back buffer. */
316       stw_pipe_blit(pipe,
317                     args->stwfb->textures[ST_ATTACHMENT_BACK_LEFT],
318                     args->stwfb->msaa_textures[ST_ATTACHMENT_BACK_LEFT]);
319 
320       /* FRONT_LEFT is resolved in flush_frontbuffer. */
321    } else if (args->stwfb->back_texture) {
322       /* Fake front texture is dirty ?? */
323       stw_pipe_blit(pipe,
324                     args->stwfb->textures[ST_ATTACHMENT_BACK_LEFT],
325                     args->stwfb->back_texture);
326    }
327 
328    if (args->stwfb->textures[ST_ATTACHMENT_BACK_LEFT])
329       pipe->flush_resource(pipe, args->stwfb->textures[ST_ATTACHMENT_BACK_LEFT]);
330 }
331 
332 void
stw_st_flush(struct st_context_iface * stctx,struct st_framebuffer_iface * stfb,unsigned flags)333 stw_st_flush(struct st_context_iface *stctx,
334              struct st_framebuffer_iface *stfb,
335              unsigned flags)
336 {
337    struct stw_st_framebuffer *stwfb = stw_st_framebuffer(stfb);
338    struct notify_before_flush_cb_args args;
339    struct pipe_fence_handle **pfence = NULL;
340    struct pipe_fence_handle *fence = NULL;
341 
342    args.stctx = stctx;
343    args.stwfb = stwfb;
344    args.flags = flags;
345 
346    if (flags & ST_FLUSH_END_OF_FRAME && !stwfb->fb->winsys_framebuffer)
347       flags |= ST_FLUSH_WAIT;
348 
349    if (flags & ST_FLUSH_WAIT)
350       pfence = &fence;
351    stctx->flush(stctx, flags, pfence, notify_before_flush_cb, &args);
352 }
353 
354 /**
355  * Present an attachment of the framebuffer.
356  */
357 static bool
stw_st_framebuffer_present_locked(HDC hdc,struct st_context_iface * stctx,struct st_framebuffer_iface * stfb,enum st_attachment_type statt)358 stw_st_framebuffer_present_locked(HDC hdc,
359                                   struct st_context_iface *stctx,
360                                   struct st_framebuffer_iface *stfb,
361                                   enum st_attachment_type statt)
362 {
363    struct stw_st_framebuffer *stwfb = stw_st_framebuffer(stfb);
364    struct pipe_resource *resource;
365 
366    assert(stw_own_mutex(&stwfb->fb->mutex));
367 
368    resource = stwfb->textures[statt];
369    if (resource) {
370       stw_framebuffer_present_locked(hdc, stwfb->fb, resource);
371    }
372    else {
373       stw_framebuffer_unlock(stwfb->fb);
374    }
375 
376    assert(!stw_own_mutex(&stwfb->fb->mutex));
377 
378    return true;
379 }
380 
381 static bool
stw_st_framebuffer_flush_front(struct st_context_iface * stctx,struct st_framebuffer_iface * stfb,enum st_attachment_type statt)382 stw_st_framebuffer_flush_front(struct st_context_iface *stctx,
383                                struct st_framebuffer_iface *stfb,
384                                enum st_attachment_type statt)
385 {
386    struct stw_st_framebuffer *stwfb = stw_st_framebuffer(stfb);
387    struct pipe_context *pipe = stctx->pipe;
388    bool ret;
389    HDC hDC;
390 
391    if (statt != ST_ATTACHMENT_FRONT_LEFT)
392       return false;
393 
394    stw_framebuffer_lock(stwfb->fb);
395 
396    /* Resolve the front buffer. */
397    if (stwfb->stvis.samples > 1) {
398       stw_pipe_blit(pipe, stwfb->textures[statt], stwfb->msaa_textures[statt]);
399    } else if (stwfb->needs_fake_front) {
400       struct pipe_resource *ptex;
401 
402       /* swap the textures */
403       ptex = stwfb->textures[ST_ATTACHMENT_FRONT_LEFT];
404       stwfb->textures[ST_ATTACHMENT_FRONT_LEFT] = stwfb->textures[ST_ATTACHMENT_BACK_LEFT];
405       stwfb->textures[ST_ATTACHMENT_BACK_LEFT] = ptex;
406 
407       /* fake front texture is now invalid */
408       p_atomic_inc(&stwfb->base.stamp);
409    }
410 
411    if (stwfb->textures[statt])
412       pipe->flush_resource(pipe, stwfb->textures[statt]);
413 
414    pipe->flush(pipe, NULL, 0);
415 
416    /* We must not cache HDCs anywhere, as they can be invalidated by the
417     * application, or screen resolution changes. */
418 
419    hDC = GetDC(stwfb->fb->hWnd);
420 
421    ret = stw_st_framebuffer_present_locked(hDC, stctx, &stwfb->base, statt);
422 
423    ReleaseDC(stwfb->fb->hWnd, hDC);
424 
425    return ret;
426 }
427 
428 /**
429  * Create a framebuffer interface.
430  */
431 struct st_framebuffer_iface *
stw_st_create_framebuffer(struct stw_framebuffer * fb)432 stw_st_create_framebuffer(struct stw_framebuffer *fb)
433 {
434    struct stw_st_framebuffer *stwfb;
435 
436    stwfb = CALLOC_STRUCT(stw_st_framebuffer);
437    if (!stwfb)
438       return NULL;
439 
440    stwfb->fb = fb;
441    stwfb->stvis = fb->pfi->stvis;
442    stwfb->base.ID = p_atomic_inc_return(&stwfb_ID);
443    stwfb->base.state_manager = stw_dev->smapi;
444 
445    stwfb->base.visual = &stwfb->stvis;
446    p_atomic_set(&stwfb->base.stamp, 1);
447    stwfb->base.flush_front = stw_st_framebuffer_flush_front;
448    stwfb->base.validate = stw_st_framebuffer_validate;
449 
450    return &stwfb->base;
451 }
452 
453 /**
454  * Destroy a framebuffer interface.
455  */
456 void
stw_st_destroy_framebuffer_locked(struct st_framebuffer_iface * stfb)457 stw_st_destroy_framebuffer_locked(struct st_framebuffer_iface *stfb)
458 {
459    struct stw_st_framebuffer *stwfb = stw_st_framebuffer(stfb);
460    int i;
461 
462    for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
463       pipe_resource_reference(&stwfb->msaa_textures[i], NULL);
464       pipe_resource_reference(&stwfb->textures[i], NULL);
465    }
466    pipe_resource_reference(&stwfb->back_texture, NULL);
467 
468    /* Notify the st manager that the framebuffer interface is no
469     * longer valid.
470     */
471    stw_dev->stapi->destroy_drawable(stw_dev->stapi, &stwfb->base);
472 
473    FREE(stwfb);
474 }
475 
476 /**
477  * Swap the buffers of the given framebuffer.
478  */
479 bool
stw_st_swap_framebuffer_locked(HDC hdc,struct st_context_iface * stctx,struct st_framebuffer_iface * stfb)480 stw_st_swap_framebuffer_locked(HDC hdc, struct st_context_iface *stctx,
481                                struct st_framebuffer_iface *stfb)
482 {
483    struct stw_st_framebuffer *stwfb = stw_st_framebuffer(stfb);
484    unsigned front = ST_ATTACHMENT_FRONT_LEFT, back = ST_ATTACHMENT_BACK_LEFT;
485    struct pipe_resource *ptex;
486    unsigned mask;
487 
488    /* swap the textures */
489    ptex = stwfb->textures[front];
490    stwfb->textures[front] = stwfb->textures[back];
491    stwfb->textures[back] = ptex;
492 
493    /* swap msaa_textures */
494    ptex = stwfb->msaa_textures[front];
495    stwfb->msaa_textures[front] = stwfb->msaa_textures[back];
496    stwfb->msaa_textures[back] = ptex;
497 
498 
499    /* Fake front texture is now dirty */
500    if (stwfb->needs_fake_front)
501       p_atomic_inc(&stwfb->base.stamp);
502 
503    /* convert to mask */
504    front = 1 << front;
505    back = 1 << back;
506 
507    /* swap the bits in mask */
508    mask = stwfb->texture_mask & ~(front | back);
509    if (stwfb->texture_mask & front)
510       mask |= back;
511    if (stwfb->texture_mask & back)
512       mask |= front;
513    stwfb->texture_mask = mask;
514 
515    front = ST_ATTACHMENT_FRONT_LEFT;
516    return stw_st_framebuffer_present_locked(hdc, stctx, &stwfb->base, front);
517 }
518 
519 
520 /**
521  * Return the pipe_resource that correspond to given buffer.
522  */
523 struct pipe_resource *
stw_get_framebuffer_resource(struct st_framebuffer_iface * stfb,enum st_attachment_type att)524 stw_get_framebuffer_resource(struct st_framebuffer_iface *stfb,
525                              enum st_attachment_type att)
526 {
527    struct stw_st_framebuffer *stwfb = stw_st_framebuffer(stfb);
528    return stwfb->textures[att];
529 }
530 
531 
532 /**
533  * Create an st_api of the gallium frontend.
534  */
535 struct st_api *
stw_st_create_api(void)536 stw_st_create_api(void)
537 {
538    return st_gl_api_create();
539 }
540