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
33 #include "stw_st.h"
34 #include "stw_device.h"
35 #include "stw_framebuffer.h"
36 #include "stw_pixelformat.h"
37
38 struct stw_st_framebuffer {
39 struct st_framebuffer_iface base;
40
41 struct stw_framebuffer *fb;
42 struct st_visual stvis;
43
44 struct pipe_resource *textures[ST_ATTACHMENT_COUNT];
45 struct pipe_resource *msaa_textures[ST_ATTACHMENT_COUNT];
46 unsigned texture_width, texture_height;
47 unsigned texture_mask;
48 };
49
50 static uint32_t stwfb_ID = 0;
51
52 /**
53 * Is the given mutex held by the calling thread?
54 */
55 bool
stw_own_mutex(const CRITICAL_SECTION * cs)56 stw_own_mutex(const CRITICAL_SECTION *cs)
57 {
58 // We can't compare OwningThread with our thread handle/id (see
59 // http://stackoverflow.com/a/12675635 ) but we can compare with the
60 // OwningThread member of a critical section we know we own.
61 CRITICAL_SECTION dummy;
62 InitializeCriticalSection(&dummy);
63 EnterCriticalSection(&dummy);
64 if (0)
65 _debug_printf("%p %p\n", cs->OwningThread, dummy.OwningThread);
66 bool ret = cs->OwningThread == dummy.OwningThread;
67 LeaveCriticalSection(&dummy);
68 DeleteCriticalSection(&dummy);
69 return ret;
70 }
71
72
73 /**
74 * Remove outdated textures and create the requested ones.
75 */
76 static void
stw_st_framebuffer_validate_locked(struct st_framebuffer_iface * stfb,unsigned width,unsigned height,unsigned mask)77 stw_st_framebuffer_validate_locked(struct st_framebuffer_iface *stfb,
78 unsigned width, unsigned height,
79 unsigned mask)
80 {
81 struct stw_st_framebuffer *stwfb = stw_st_framebuffer(stfb);
82 struct pipe_resource templ;
83 unsigned i;
84
85 /* remove outdated textures */
86 if (stwfb->texture_width != width || stwfb->texture_height != height) {
87 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
88 pipe_resource_reference(&stwfb->msaa_textures[i], NULL);
89 pipe_resource_reference(&stwfb->textures[i], NULL);
90 }
91 }
92
93 memset(&templ, 0, sizeof(templ));
94 templ.target = PIPE_TEXTURE_2D;
95 templ.width0 = width;
96 templ.height0 = height;
97 templ.depth0 = 1;
98 templ.array_size = 1;
99 templ.last_level = 0;
100
101 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
102 enum pipe_format format;
103 unsigned bind;
104
105 /* the texture already exists or not requested */
106 if (stwfb->textures[i] || !(mask & (1 << i))) {
107 /* remember the texture */
108 if (stwfb->textures[i])
109 mask |= (1 << i);
110 continue;
111 }
112
113 switch (i) {
114 case ST_ATTACHMENT_FRONT_LEFT:
115 case ST_ATTACHMENT_BACK_LEFT:
116 format = stwfb->stvis.color_format;
117 bind = PIPE_BIND_DISPLAY_TARGET |
118 PIPE_BIND_SAMPLER_VIEW |
119 PIPE_BIND_RENDER_TARGET;
120 break;
121 case ST_ATTACHMENT_DEPTH_STENCIL:
122 format = stwfb->stvis.depth_stencil_format;
123 bind = PIPE_BIND_DEPTH_STENCIL;
124 break;
125 default:
126 format = PIPE_FORMAT_NONE;
127 break;
128 }
129
130 if (format != PIPE_FORMAT_NONE) {
131 templ.format = format;
132
133 if (bind != PIPE_BIND_DEPTH_STENCIL && stwfb->stvis.samples > 1) {
134 templ.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;
135 templ.nr_samples = templ.nr_storage_samples =
136 stwfb->stvis.samples;
137
138 stwfb->msaa_textures[i] =
139 stw_dev->screen->resource_create(stw_dev->screen, &templ);
140 }
141
142 templ.bind = bind;
143 templ.nr_samples = templ.nr_storage_samples = 1;
144 stwfb->textures[i] =
145 stw_dev->screen->resource_create(stw_dev->screen, &templ);
146 }
147 }
148
149 stwfb->texture_width = width;
150 stwfb->texture_height = height;
151 stwfb->texture_mask = mask;
152 }
153
154 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)155 stw_st_framebuffer_validate(struct st_context_iface *stctx,
156 struct st_framebuffer_iface *stfb,
157 const enum st_attachment_type *statts,
158 unsigned count,
159 struct pipe_resource **out)
160 {
161 struct stw_st_framebuffer *stwfb = stw_st_framebuffer(stfb);
162 unsigned statt_mask, i;
163
164 statt_mask = 0x0;
165 for (i = 0; i < count; i++)
166 statt_mask |= 1 << statts[i];
167
168 stw_framebuffer_lock(stwfb->fb);
169
170 if (stwfb->fb->must_resize || (statt_mask & ~stwfb->texture_mask)) {
171 stw_st_framebuffer_validate_locked(&stwfb->base,
172 stwfb->fb->width, stwfb->fb->height, statt_mask);
173 stwfb->fb->must_resize = FALSE;
174 }
175
176 struct pipe_resource **textures =
177 stwfb->stvis.samples > 1 ? stwfb->msaa_textures
178 : stwfb->textures;
179
180 for (i = 0; i < count; i++)
181 pipe_resource_reference(&out[i], textures[statts[i]]);
182
183 stw_framebuffer_unlock(stwfb->fb);
184
185 return true;
186 }
187
188 static void
stw_pipe_blit(struct pipe_context * pipe,struct pipe_resource * dst,struct pipe_resource * src)189 stw_pipe_blit(struct pipe_context *pipe,
190 struct pipe_resource *dst,
191 struct pipe_resource *src)
192 {
193 struct pipe_blit_info blit;
194
195 /* From the GL spec, version 4.2, section 4.1.11 (Additional Multisample
196 * Fragment Operations):
197 *
198 * If a framebuffer object is not bound, after all operations have
199 * been completed on the multisample buffer, the sample values for
200 * each color in the multisample buffer are combined to produce a
201 * single color value, and that value is written into the
202 * corresponding color buffers selected by DrawBuffer or
203 * DrawBuffers. An implementation may defer the writing of the color
204 * buffers until a later time, but the state of the framebuffer must
205 * behave as if the color buffers were updated as each fragment was
206 * processed. The method of combination is not specified. If the
207 * framebuffer contains sRGB values, then it is recommended that the
208 * an average of sample values is computed in a linearized space, as
209 * for blending (see section 4.1.7).
210 *
211 * In other words, to do a resolve operation in a linear space, we have
212 * to set sRGB formats if the original resources were sRGB, so don't use
213 * util_format_linear.
214 */
215
216 memset(&blit, 0, sizeof(blit));
217 blit.dst.resource = dst;
218 blit.dst.box.width = dst->width0;
219 blit.dst.box.height = dst->height0;
220 blit.dst.box.depth = 1;
221 blit.dst.format = dst->format;
222 blit.src.resource = src;
223 blit.src.box.width = src->width0;
224 blit.src.box.height = src->height0;
225 blit.src.box.depth = 1;
226 blit.src.format = src->format;
227 blit.mask = PIPE_MASK_RGBA;
228 blit.filter = PIPE_TEX_FILTER_NEAREST;
229
230 pipe->blit(pipe, &blit);
231 }
232
233 /**
234 * Present an attachment of the framebuffer.
235 */
236 static bool
stw_st_framebuffer_present_locked(HDC hdc,struct st_context_iface * stctx,struct st_framebuffer_iface * stfb,enum st_attachment_type statt)237 stw_st_framebuffer_present_locked(HDC hdc,
238 struct st_context_iface *stctx,
239 struct st_framebuffer_iface *stfb,
240 enum st_attachment_type statt)
241 {
242 struct stw_st_framebuffer *stwfb = stw_st_framebuffer(stfb);
243 struct pipe_resource *resource;
244
245 assert(stw_own_mutex(&stwfb->fb->mutex));
246
247 if (stwfb->stvis.samples > 1) {
248 stw_pipe_blit(stctx->pipe,
249 stwfb->textures[statt],
250 stwfb->msaa_textures[statt]);
251 }
252
253 resource = stwfb->textures[statt];
254 if (resource) {
255 stw_framebuffer_present_locked(hdc, stwfb->fb, resource);
256 }
257 else {
258 stw_framebuffer_unlock(stwfb->fb);
259 }
260
261 assert(!stw_own_mutex(&stwfb->fb->mutex));
262
263 return true;
264 }
265
266 static bool
stw_st_framebuffer_flush_front(struct st_context_iface * stctx,struct st_framebuffer_iface * stfb,enum st_attachment_type statt)267 stw_st_framebuffer_flush_front(struct st_context_iface *stctx,
268 struct st_framebuffer_iface *stfb,
269 enum st_attachment_type statt)
270 {
271 struct stw_st_framebuffer *stwfb = stw_st_framebuffer(stfb);
272 bool ret;
273 HDC hDC;
274
275 stw_framebuffer_lock(stwfb->fb);
276
277 /* We must not cache HDCs anywhere, as they can be invalidated by the
278 * application, or screen resolution changes. */
279
280 hDC = GetDC(stwfb->fb->hWnd);
281
282 ret = stw_st_framebuffer_present_locked(hDC, stctx, &stwfb->base, statt);
283
284 ReleaseDC(stwfb->fb->hWnd, hDC);
285
286 return ret;
287 }
288
289 /**
290 * Create a framebuffer interface.
291 */
292 struct st_framebuffer_iface *
stw_st_create_framebuffer(struct stw_framebuffer * fb)293 stw_st_create_framebuffer(struct stw_framebuffer *fb)
294 {
295 struct stw_st_framebuffer *stwfb;
296
297 stwfb = CALLOC_STRUCT(stw_st_framebuffer);
298 if (!stwfb)
299 return NULL;
300
301 stwfb->fb = fb;
302 stwfb->stvis = fb->pfi->stvis;
303 stwfb->base.ID = p_atomic_inc_return(&stwfb_ID);
304 stwfb->base.state_manager = stw_dev->smapi;
305
306 stwfb->base.visual = &stwfb->stvis;
307 p_atomic_set(&stwfb->base.stamp, 1);
308 stwfb->base.flush_front = stw_st_framebuffer_flush_front;
309 stwfb->base.validate = stw_st_framebuffer_validate;
310
311 return &stwfb->base;
312 }
313
314 /**
315 * Destroy a framebuffer interface.
316 */
317 void
stw_st_destroy_framebuffer_locked(struct st_framebuffer_iface * stfb)318 stw_st_destroy_framebuffer_locked(struct st_framebuffer_iface *stfb)
319 {
320 struct stw_st_framebuffer *stwfb = stw_st_framebuffer(stfb);
321 int i;
322
323 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
324 pipe_resource_reference(&stwfb->msaa_textures[i], NULL);
325 pipe_resource_reference(&stwfb->textures[i], NULL);
326 }
327
328 /* Notify the st manager that the framebuffer interface is no
329 * longer valid.
330 */
331 stw_dev->stapi->destroy_drawable(stw_dev->stapi, &stwfb->base);
332
333 FREE(stwfb);
334 }
335
336 /**
337 * Swap the buffers of the given framebuffer.
338 */
339 bool
stw_st_swap_framebuffer_locked(HDC hdc,struct st_context_iface * stctx,struct st_framebuffer_iface * stfb)340 stw_st_swap_framebuffer_locked(HDC hdc, struct st_context_iface *stctx,
341 struct st_framebuffer_iface *stfb)
342 {
343 struct stw_st_framebuffer *stwfb = stw_st_framebuffer(stfb);
344 unsigned front = ST_ATTACHMENT_FRONT_LEFT, back = ST_ATTACHMENT_BACK_LEFT;
345 struct pipe_resource *ptex;
346 unsigned mask;
347
348 /* swap the textures */
349 ptex = stwfb->textures[front];
350 stwfb->textures[front] = stwfb->textures[back];
351 stwfb->textures[back] = ptex;
352
353 /* swap msaa_textures */
354 ptex = stwfb->msaa_textures[front];
355 stwfb->msaa_textures[front] = stwfb->msaa_textures[back];
356 stwfb->msaa_textures[back] = ptex;
357
358 /* convert to mask */
359 front = 1 << front;
360 back = 1 << back;
361
362 /* swap the bits in mask */
363 mask = stwfb->texture_mask & ~(front | back);
364 if (stwfb->texture_mask & front)
365 mask |= back;
366 if (stwfb->texture_mask & back)
367 mask |= front;
368 stwfb->texture_mask = mask;
369
370 front = ST_ATTACHMENT_FRONT_LEFT;
371 return stw_st_framebuffer_present_locked(hdc, stctx, &stwfb->base, front);
372 }
373
374
375 /**
376 * Return the pipe_resource that correspond to given buffer.
377 */
378 struct pipe_resource *
stw_get_framebuffer_resource(struct st_framebuffer_iface * stfb,enum st_attachment_type att)379 stw_get_framebuffer_resource(struct st_framebuffer_iface *stfb,
380 enum st_attachment_type att)
381 {
382 struct stw_st_framebuffer *stwfb = stw_st_framebuffer(stfb);
383 return stwfb->textures[att];
384 }
385
386
387 /**
388 * Create an st_api of the gallium frontend.
389 */
390 struct st_api *
stw_st_create_api(void)391 stw_st_create_api(void)
392 {
393 return st_gl_api_create();
394 }
395