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