1
/**************************************************************************
3
* Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
6
* Permission is hereby granted, free of charge, to any person obtaining a
7
* copy of this software and associated documentation files (the
8
* "Software"), to deal in the Software without restriction, including
9
* without limitation the rights to use, copy, modify, merge, publish,
10
* distribute, sub license, and/or sell copies of the Software, and to
11
* permit persons to whom the Software is furnished to do so, subject to
12
* the following conditions:
14
* The above copyright notice and this permission notice (including the
15
* next paragraph) shall be included in all copies or substantial portions
18
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21
* IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
**************************************************************************/
29
#include "main/imports.h"
30
#include "main/buffers.h"
31
#include "main/context.h"
32
#include "main/framebuffer.h"
33
#include "main/renderbuffer.h"
34
#include "st_context.h"
35
#include "st_cb_fbo.h"
36
#include "st_public.h"
37
#include "pipe/p_defines.h"
38
#include "util/u_inlines.h"
41
struct st_framebuffer *
42
st_create_framebuffer( const __GLcontextModes *visual,
43
enum pipe_format colorFormat,
44
enum pipe_format depthFormat,
45
enum pipe_format stencilFormat,
46
uint width, uint height,
49
struct st_framebuffer *stfb = ST_CALLOC_STRUCT(st_framebuffer);
51
int samples = st_get_msaa();
54
if (visual->sampleBuffers)
55
samples = visual->samples;
57
_mesa_initialize_window_framebuffer(&stfb->Base, visual);
59
if (visual->doubleBufferMode) {
60
struct gl_renderbuffer *rb
61
= st_new_renderbuffer_fb(colorFormat, samples, FALSE);
62
_mesa_add_renderbuffer(&stfb->Base, BUFFER_BACK_LEFT, rb);
65
/* Only allocate front buffer right now if we're single buffered.
66
* If double-buffered, allocate front buffer on demand later.
67
* See check_create_front_buffers() and st_set_framebuffer_surface().
69
struct gl_renderbuffer *rb
70
= st_new_renderbuffer_fb(colorFormat, samples, FALSE);
71
_mesa_add_renderbuffer(&stfb->Base, BUFFER_FRONT_LEFT, rb);
74
if (depthFormat == stencilFormat && depthFormat != PIPE_FORMAT_NONE) {
75
/* combined depth/stencil buffer */
76
struct gl_renderbuffer *depthStencilRb
77
= st_new_renderbuffer_fb(depthFormat, samples, FALSE);
78
/* note: bind RB to two attachment points */
79
_mesa_add_renderbuffer(&stfb->Base, BUFFER_DEPTH, depthStencilRb);
80
_mesa_add_renderbuffer(&stfb->Base, BUFFER_STENCIL, depthStencilRb);
83
/* separate depth and/or stencil */
85
if (visual->depthBits == 32) {
86
/* 32-bit depth buffer */
87
struct gl_renderbuffer *depthRb
88
= st_new_renderbuffer_fb(depthFormat, samples, FALSE);
89
_mesa_add_renderbuffer(&stfb->Base, BUFFER_DEPTH, depthRb);
91
else if (visual->depthBits == 24) {
92
/* 24-bit depth buffer, ignore stencil bits */
93
struct gl_renderbuffer *depthRb
94
= st_new_renderbuffer_fb(depthFormat, samples, FALSE);
95
_mesa_add_renderbuffer(&stfb->Base, BUFFER_DEPTH, depthRb);
97
else if (visual->depthBits > 0) {
98
/* 16-bit depth buffer */
99
struct gl_renderbuffer *depthRb
100
= st_new_renderbuffer_fb(depthFormat, samples, FALSE);
101
_mesa_add_renderbuffer(&stfb->Base, BUFFER_DEPTH, depthRb);
104
if (visual->stencilBits > 0) {
106
struct gl_renderbuffer *stencilRb
107
= st_new_renderbuffer_fb(stencilFormat, samples, FALSE);
108
_mesa_add_renderbuffer(&stfb->Base, BUFFER_STENCIL, stencilRb);
112
if (visual->accumRedBits > 0) {
113
/* 16-bit/channel accum */
114
/* TODO: query the pipe screen for accumulation buffer format support */
115
struct gl_renderbuffer *accumRb
116
= st_new_renderbuffer_fb(PIPE_FORMAT_R16G16B16A16_SNORM, 0, TRUE);
117
_mesa_add_renderbuffer(&stfb->Base, BUFFER_ACCUM, accumRb);
120
for (i = 0; i < visual->numAuxBuffers; i++) {
121
struct gl_renderbuffer *aux
122
= st_new_renderbuffer_fb(colorFormat, 0, FALSE);
123
_mesa_add_renderbuffer(&stfb->Base, BUFFER_AUX0 + i, aux);
126
stfb->Base.Initialized = GL_TRUE;
127
stfb->InitWidth = width;
128
stfb->InitHeight = height;
129
stfb->Private = private;
135
void st_resize_framebuffer( struct st_framebuffer *stfb,
136
uint width, uint height )
138
if (stfb->Base.Width != width || stfb->Base.Height != height) {
139
GET_CURRENT_CONTEXT(ctx);
141
_mesa_check_init_viewport(ctx, width, height);
143
_mesa_resize_framebuffer(ctx, &stfb->Base, width, height);
145
assert(stfb->Base.Width == width);
146
assert(stfb->Base.Height == height);
152
void st_unreference_framebuffer( struct st_framebuffer *stfb )
154
_mesa_reference_framebuffer((struct gl_framebuffer **) &stfb, NULL);
160
* Set/replace a framebuffer surface.
161
* The user of the state tracker can use this instead of
162
* st_resize_framebuffer() to provide new surfaces when a window is resized.
163
* \param surfIndex an ST_SURFACE_x index
166
st_set_framebuffer_surface(struct st_framebuffer *stfb,
167
uint surfIndex, struct pipe_surface *surf)
169
GET_CURRENT_CONTEXT(ctx);
170
struct st_renderbuffer *strb;
173
assert(ST_SURFACE_FRONT_LEFT == BUFFER_FRONT_LEFT);
174
assert(ST_SURFACE_BACK_LEFT == BUFFER_BACK_LEFT);
175
assert(ST_SURFACE_FRONT_RIGHT == BUFFER_FRONT_RIGHT);
176
assert(ST_SURFACE_BACK_RIGHT == BUFFER_BACK_RIGHT);
177
assert(ST_SURFACE_DEPTH == BUFFER_DEPTH);
179
assert(surfIndex < BUFFER_COUNT);
181
strb = st_renderbuffer(stfb->Base.Attachment[surfIndex].Renderbuffer);
184
/* create new renderbuffer for this surface now */
185
const GLuint numSamples = stfb->Base.Visual.samples;
186
struct gl_renderbuffer *rb =
187
st_new_renderbuffer_fb(surf->format, numSamples, FALSE);
190
_mesa_warning(ctx, "Out of memory allocating renderbuffer");
193
_mesa_add_renderbuffer(&stfb->Base, surfIndex, rb);
194
strb = st_renderbuffer(rb);
197
/* replace the renderbuffer's surface/texture pointers */
198
pipe_surface_reference( &strb->surface, surf );
199
pipe_texture_reference( &strb->texture, surf->texture );
202
/* If ctx isn't set, we've likely not made current yet.
203
* But when we do, we need to start setting this dirty bit
204
* to ensure the renderbuffer attachements are up-to-date
205
* via update_framebuffer.
206
* Core Mesa's state validation will update the parent framebuffer's
209
ctx->st->dirty.st |= ST_NEW_FRAMEBUFFER;
210
ctx->NewState |= _NEW_BUFFERS;
213
/* update renderbuffer's width/height */
214
strb->Base.Width = surf->width;
215
strb->Base.Height = surf->height;
221
* Return the pipe_surface for the given renderbuffer.
224
st_get_framebuffer_surface(struct st_framebuffer *stfb, uint surfIndex, struct pipe_surface **surface)
226
struct st_renderbuffer *strb;
228
assert(surfIndex <= ST_SURFACE_DEPTH);
230
/* sanity checks, ST tokens should match Mesa tokens */
231
assert(ST_SURFACE_FRONT_LEFT == BUFFER_FRONT_LEFT);
232
assert(ST_SURFACE_BACK_RIGHT == BUFFER_BACK_RIGHT);
234
strb = st_renderbuffer(stfb->Base.Attachment[surfIndex].Renderbuffer);
236
*surface = strb->surface;
245
st_get_framebuffer_texture(struct st_framebuffer *stfb, uint surfIndex, struct pipe_texture **texture)
247
struct st_renderbuffer *strb;
249
assert(surfIndex <= ST_SURFACE_DEPTH);
251
/* sanity checks, ST tokens should match Mesa tokens */
252
assert(ST_SURFACE_FRONT_LEFT == BUFFER_FRONT_LEFT);
253
assert(ST_SURFACE_BACK_RIGHT == BUFFER_BACK_RIGHT);
255
strb = st_renderbuffer(stfb->Base.Attachment[surfIndex].Renderbuffer);
257
*texture = strb->texture;
266
* This function is to be called prior to SwapBuffers on the given
267
* framebuffer. It checks if the current context is bound to the framebuffer
268
* and flushes rendering if needed.
271
st_notify_swapbuffers(struct st_framebuffer *stfb)
273
GET_CURRENT_CONTEXT(ctx);
275
if (ctx && ctx->DrawBuffer == &stfb->Base) {
277
PIPE_FLUSH_RENDER_CACHE |
278
PIPE_FLUSH_SWAPBUFFERS |
281
if (st_renderbuffer(stfb->Base.Attachment[BUFFER_BACK_LEFT].Renderbuffer))
282
ctx->st->frontbuffer_status = FRONT_STATUS_COPY_OF_BACK;
288
* Swap the front/back color buffers. Exchange the front/back pointers
289
* and update some derived state.
290
* No need to call st_notify_swapbuffers() first.
292
* For a single-buffered framebuffer, no swap occurs, but we still return
293
* the pointer(s) to the front color buffer(s).
295
* \param front_left returns pointer to front-left renderbuffer after swap
296
* \param front_right returns pointer to front-right renderbuffer after swap
299
st_swapbuffers(struct st_framebuffer *stfb,
300
struct pipe_surface **front_left,
301
struct pipe_surface **front_right)
303
struct gl_framebuffer *fb = &stfb->Base;
305
GET_CURRENT_CONTEXT(ctx);
307
if (ctx && ctx->DrawBuffer == &stfb->Base) {
309
PIPE_FLUSH_RENDER_CACHE |
310
PIPE_FLUSH_SWAPBUFFERS |
315
if (!fb->Visual.doubleBufferMode) {
316
/* single buffer mode - return pointers to front surfaces */
318
struct st_renderbuffer *strb =
319
st_renderbuffer(fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer);
320
*front_left = strb->surface;
323
struct st_renderbuffer *strb =
324
st_renderbuffer(fb->Attachment[BUFFER_FRONT_RIGHT].Renderbuffer);
325
*front_right = strb ? strb->surface : NULL;
330
/* swap left buffers */
331
if (fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer &&
332
fb->Attachment[BUFFER_BACK_LEFT].Renderbuffer) {
333
struct gl_renderbuffer *rbTemp;
334
rbTemp = fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer;
335
fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer =
336
fb->Attachment[BUFFER_BACK_LEFT].Renderbuffer;
337
fb->Attachment[BUFFER_BACK_LEFT].Renderbuffer = rbTemp;
339
struct st_renderbuffer *strb =
340
st_renderbuffer(fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer);
341
*front_left = strb->surface;
343
/* mark back buffer contents as undefined */
345
struct st_renderbuffer *back =
346
st_renderbuffer(fb->Attachment[BUFFER_BACK_LEFT].Renderbuffer);
347
back->defined = GL_FALSE;
351
/* no front buffer, display the back buffer */
353
struct st_renderbuffer *strb =
354
st_renderbuffer(fb->Attachment[BUFFER_BACK_LEFT].Renderbuffer);
355
*front_left = strb->surface;
359
/* swap right buffers (for stereo) */
360
if (fb->Attachment[BUFFER_FRONT_RIGHT].Renderbuffer &&
361
fb->Attachment[BUFFER_BACK_RIGHT].Renderbuffer) {
362
struct gl_renderbuffer *rbTemp;
363
rbTemp = fb->Attachment[BUFFER_FRONT_RIGHT].Renderbuffer;
364
fb->Attachment[BUFFER_FRONT_RIGHT].Renderbuffer =
365
fb->Attachment[BUFFER_BACK_RIGHT].Renderbuffer;
366
fb->Attachment[BUFFER_BACK_RIGHT].Renderbuffer = rbTemp;
368
struct st_renderbuffer *strb =
369
st_renderbuffer(fb->Attachment[BUFFER_FRONT_RIGHT].Renderbuffer);
370
*front_right = strb->surface;
372
/* mark back buffer contents as undefined */
374
struct st_renderbuffer *back =
375
st_renderbuffer(fb->Attachment[BUFFER_BACK_RIGHT].Renderbuffer);
376
back->defined = GL_FALSE;
380
/* no front right buffer, display back right buffer (if exists) */
382
struct st_renderbuffer *strb =
383
st_renderbuffer(fb->Attachment[BUFFER_BACK_RIGHT].Renderbuffer);
384
*front_right = strb ? strb->surface : NULL;
388
/* Update the _ColorDrawBuffers[] array and _ColorReadBuffer pointer */
389
_mesa_update_framebuffer(ctx);
391
/* Make sure we draw into the new back surface */
392
st_invalidate_state(ctx, _NEW_BUFFERS);
396
void *st_framebuffer_private( struct st_framebuffer *stfb )
398
return stfb->Private;
401
void st_get_framebuffer_dimensions( struct st_framebuffer *stfb,
405
*width = stfb->Base.Width;
406
*height = stfb->Base.Height;