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