2 * Mesa 3-D graphics library
4 * Copyright (C) 2010 LunarG Inc.
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:
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
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.
25 * Chia-I Wu <olv@lunarg.com>
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 */
34 #include "stw_device.h"
35 #include "stw_framebuffer.h"
36 #include "stw_pixelformat.h"
38 struct stw_st_framebuffer
{
39 struct st_framebuffer_iface base
;
41 struct stw_framebuffer
*fb
;
42 struct st_visual stvis
;
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
;
50 static uint32_t stwfb_ID
= 0;
53 * Is the given mutex held by the calling thread?
56 stw_own_mutex(const CRITICAL_SECTION
*cs
)
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
);
65 _debug_printf("%p %p\n", cs
->OwningThread
, dummy
.OwningThread
);
66 bool ret
= cs
->OwningThread
== dummy
.OwningThread
;
67 LeaveCriticalSection(&dummy
);
68 DeleteCriticalSection(&dummy
);
74 * Remove outdated textures and create the requested ones.
77 stw_st_framebuffer_validate_locked(struct st_framebuffer_iface
*stfb
,
78 unsigned width
, unsigned height
,
81 struct stw_st_framebuffer
*stwfb
= stw_st_framebuffer(stfb
);
82 struct pipe_resource templ
;
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
);
93 memset(&templ
, 0, sizeof(templ
));
94 templ
.target
= PIPE_TEXTURE_2D
;
96 templ
.height0
= height
;
101 for (i
= 0; i
< ST_ATTACHMENT_COUNT
; i
++) {
102 enum pipe_format format
;
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
])
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
;
121 case ST_ATTACHMENT_DEPTH_STENCIL
:
122 format
= stwfb
->stvis
.depth_stencil_format
;
123 bind
= PIPE_BIND_DEPTH_STENCIL
;
126 format
= PIPE_FORMAT_NONE
;
130 if (format
!= PIPE_FORMAT_NONE
) {
131 templ
.format
= format
;
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
;
138 stwfb
->msaa_textures
[i
] =
139 stw_dev
->screen
->resource_create(stw_dev
->screen
, &templ
);
143 templ
.nr_samples
= templ
.nr_storage_samples
= 1;
145 stw_dev
->screen
->resource_create(stw_dev
->screen
, &templ
);
149 stwfb
->texture_width
= width
;
150 stwfb
->texture_height
= height
;
151 stwfb
->texture_mask
= mask
;
155 stw_st_framebuffer_validate(struct st_context_iface
*stctx
,
156 struct st_framebuffer_iface
*stfb
,
157 const enum st_attachment_type
*statts
,
159 struct pipe_resource
**out
)
161 struct stw_st_framebuffer
*stwfb
= stw_st_framebuffer(stfb
);
162 unsigned statt_mask
, i
;
165 for (i
= 0; i
< count
; i
++)
166 statt_mask
|= 1 << statts
[i
];
168 stw_framebuffer_lock(stwfb
->fb
);
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
;
176 struct pipe_resource
**textures
=
177 stwfb
->stvis
.samples
> 1 ? stwfb
->msaa_textures
180 for (i
= 0; i
< count
; i
++)
181 pipe_resource_reference(&out
[i
], textures
[statts
[i
]]);
183 stw_framebuffer_unlock(stwfb
->fb
);
189 stw_pipe_blit(struct pipe_context
*pipe
,
190 struct pipe_resource
*dst
,
191 struct pipe_resource
*src
)
193 struct pipe_blit_info blit
;
195 /* From the GL spec, version 4.2, section 4.1.11 (Additional Multisample
196 * Fragment Operations):
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).
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.
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
;
230 pipe
->blit(pipe
, &blit
);
234 * Present an attachment of the framebuffer.
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
)
242 struct stw_st_framebuffer
*stwfb
= stw_st_framebuffer(stfb
);
243 struct pipe_resource
*resource
;
245 assert(stw_own_mutex(&stwfb
->fb
->mutex
));
247 if (stwfb
->stvis
.samples
> 1) {
248 stw_pipe_blit(stctx
->pipe
,
249 stwfb
->textures
[statt
],
250 stwfb
->msaa_textures
[statt
]);
253 resource
= stwfb
->textures
[statt
];
255 stw_framebuffer_present_locked(hdc
, stwfb
->fb
, resource
);
258 stw_framebuffer_unlock(stwfb
->fb
);
261 assert(!stw_own_mutex(&stwfb
->fb
->mutex
));
267 stw_st_framebuffer_flush_front(struct st_context_iface
*stctx
,
268 struct st_framebuffer_iface
*stfb
,
269 enum st_attachment_type statt
)
271 struct stw_st_framebuffer
*stwfb
= stw_st_framebuffer(stfb
);
275 stw_framebuffer_lock(stwfb
->fb
);
277 /* We must not cache HDCs anywhere, as they can be invalidated by the
278 * application, or screen resolution changes. */
280 hDC
= GetDC(stwfb
->fb
->hWnd
);
282 ret
= stw_st_framebuffer_present_locked(hDC
, stctx
, &stwfb
->base
, statt
);
284 ReleaseDC(stwfb
->fb
->hWnd
, hDC
);
290 * Create a framebuffer interface.
292 struct st_framebuffer_iface
*
293 stw_st_create_framebuffer(struct stw_framebuffer
*fb
)
295 struct stw_st_framebuffer
*stwfb
;
297 stwfb
= CALLOC_STRUCT(stw_st_framebuffer
);
302 stwfb
->stvis
= fb
->pfi
->stvis
;
303 stwfb
->base
.ID
= p_atomic_inc_return(&stwfb_ID
);
304 stwfb
->base
.state_manager
= stw_dev
->smapi
;
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
;
315 * Destroy a framebuffer interface.
318 stw_st_destroy_framebuffer_locked(struct st_framebuffer_iface
*stfb
)
320 struct stw_st_framebuffer
*stwfb
= stw_st_framebuffer(stfb
);
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
);
328 /* Notify the st manager that the framebuffer interface is no
331 stw_dev
->stapi
->destroy_drawable(stw_dev
->stapi
, &stwfb
->base
);
337 * Swap the buffers of the given framebuffer.
340 stw_st_swap_framebuffer_locked(HDC hdc
, struct st_context_iface
*stctx
,
341 struct st_framebuffer_iface
*stfb
)
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
;
348 /* swap the textures */
349 ptex
= stwfb
->textures
[front
];
350 stwfb
->textures
[front
] = stwfb
->textures
[back
];
351 stwfb
->textures
[back
] = ptex
;
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
;
358 /* convert to mask */
362 /* swap the bits in mask */
363 mask
= stwfb
->texture_mask
& ~(front
| back
);
364 if (stwfb
->texture_mask
& front
)
366 if (stwfb
->texture_mask
& back
)
368 stwfb
->texture_mask
= mask
;
370 front
= ST_ATTACHMENT_FRONT_LEFT
;
371 return stw_st_framebuffer_present_locked(hdc
, stctx
, &stwfb
->base
, front
);
376 * Return the pipe_resource that correspond to given buffer.
378 struct pipe_resource
*
379 stw_get_framebuffer_resource(struct st_framebuffer_iface
*stfb
,
380 enum st_attachment_type att
)
382 struct stw_st_framebuffer
*stwfb
= stw_st_framebuffer(stfb
);
383 return stwfb
->textures
[att
];
388 * Create an st_api of the state tracker.
391 stw_st_create_api(void)
393 return st_gl_api_create();