fix GLX server resize/crash when resizing windows
[mesa.git] / src / mesa / main / framebuffer.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.5
4 *
5 * Copyright (C) 1999-2005 Brian Paul All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25
26 /**
27 * Functions for allocating/managing framebuffers and renderbuffers.
28 * Also, routines for reading/writing renderbuffer data as ubytes,
29 * ushorts, uints, etc.
30 */
31
32
33 #include "glheader.h"
34 #include "imports.h"
35 #include "context.h"
36 #include "mtypes.h"
37 #include "fbobject.h"
38 #include "framebuffer.h"
39 #include "renderbuffer.h"
40
41
42
43 /**
44 * Compute/set the _DepthMax field for the given framebuffer.
45 * This value depends on the Z buffer resolution.
46 */
47 static void
48 compute_depth_max(struct gl_framebuffer *fb)
49 {
50 if (fb->Visual.depthBits == 0) {
51 /* Special case. Even if we don't have a depth buffer we need
52 * good values for DepthMax for Z vertex transformation purposes
53 * and for per-fragment fog computation.
54 */
55 fb->_DepthMax = (1 << 16) - 1;
56 }
57 else if (fb->Visual.depthBits < 32) {
58 fb->_DepthMax = (1 << fb->Visual.depthBits) - 1;
59 }
60 else {
61 /* Special case since shift values greater than or equal to the
62 * number of bits in the left hand expression's type are undefined.
63 */
64 fb->_DepthMax = 0xffffffff;
65 }
66 fb->_DepthMaxF = (GLfloat) fb->_DepthMax;
67 fb->_MRD = 1.0; /* Minimum resolvable depth value, for polygon offset */
68 }
69
70
71 /**
72 * Create and initialize a gl_framebuffer object.
73 * This is intended for creating _window_system_ framebuffers, not generic
74 * framebuffer objects ala GL_EXT_framebuffer_object.
75 *
76 * \sa _mesa_new_framebuffer
77 */
78 struct gl_framebuffer *
79 _mesa_create_framebuffer(const GLvisual *visual)
80 {
81 struct gl_framebuffer *fb = CALLOC_STRUCT(gl_framebuffer);
82 assert(visual);
83 if (fb) {
84 _mesa_initialize_framebuffer(fb, visual);
85 }
86 return fb;
87 }
88
89
90 /**
91 * Allocate a new gl_framebuffer object.
92 * This is the default function for ctx->Driver.NewFramebuffer().
93 * This is for allocating user-created framebuffers, not window-system
94 * framebuffers!
95 * \sa _mesa_create_framebuffer
96 */
97 struct gl_framebuffer *
98 _mesa_new_framebuffer(GLcontext *ctx, GLuint name)
99 {
100 struct gl_framebuffer *fb;
101 assert(name != 0);
102 fb = CALLOC_STRUCT(gl_framebuffer);
103 if (fb) {
104 fb->Name = name;
105 fb->RefCount = 1;
106 fb->ColorDrawBuffer[0] = GL_COLOR_ATTACHMENT0_EXT;
107 fb->_ColorDrawBufferMask[0] = BUFFER_BIT_COLOR0;
108 fb->ColorReadBuffer = GL_COLOR_ATTACHMENT0_EXT;
109 fb->_ColorReadBufferIndex = BUFFER_COLOR0;
110 fb->Delete = _mesa_destroy_framebuffer;
111 }
112 return fb;
113 }
114
115
116 /**
117 * Initialize a gl_framebuffer object. Typically used to initialize
118 * window system-created framebuffers, not user-created framebuffers.
119 * \sa _mesa_create_framebuffer
120 */
121 void
122 _mesa_initialize_framebuffer(struct gl_framebuffer *fb, const GLvisual *visual)
123 {
124 assert(fb);
125 assert(visual);
126
127 _mesa_bzero(fb, sizeof(struct gl_framebuffer));
128
129 /* save the visual */
130 fb->Visual = *visual;
131
132 /* Init glRead/DrawBuffer state */
133 if (visual->doubleBufferMode) {
134 fb->ColorDrawBuffer[0] = GL_BACK;
135 fb->_ColorDrawBufferMask[0] = BUFFER_BIT_BACK_LEFT;
136 fb->ColorReadBuffer = GL_BACK;
137 fb->_ColorReadBufferIndex = BUFFER_BACK_LEFT;
138 }
139 else {
140 fb->ColorDrawBuffer[0] = GL_FRONT;
141 fb->_ColorDrawBufferMask[0] = BUFFER_BIT_FRONT_LEFT;
142 fb->ColorReadBuffer = GL_FRONT;
143 fb->_ColorReadBufferIndex = BUFFER_FRONT_LEFT;
144 }
145
146 fb->Delete = _mesa_destroy_framebuffer;
147 fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT;
148
149 compute_depth_max(fb);
150 }
151
152
153 /**
154 * Deallocate buffer and everything attached to it.
155 * Typically called via the gl_framebuffer->Delete() method.
156 */
157 void
158 _mesa_destroy_framebuffer(struct gl_framebuffer *fb)
159 {
160 if (fb) {
161 _mesa_free_framebuffer_data(fb);
162 FREE(fb);
163 }
164 }
165
166
167 /**
168 * Free all the data hanging off the given gl_framebuffer, but don't free
169 * the gl_framebuffer object itself.
170 */
171 void
172 _mesa_free_framebuffer_data(struct gl_framebuffer *fb)
173 {
174 GLuint i;
175
176 assert(fb);
177
178 for (i = 0; i < BUFFER_COUNT; i++) {
179 struct gl_renderbuffer_attachment *att = &fb->Attachment[i];
180 if (att->Type == GL_RENDERBUFFER_EXT && att->Renderbuffer) {
181 struct gl_renderbuffer *rb = att->Renderbuffer;
182 rb->RefCount--;
183 if (rb->RefCount == 0) {
184 rb->Delete(rb);
185 }
186 }
187 att->Type = GL_NONE;
188 att->Renderbuffer = NULL;
189 }
190 }
191
192
193 /**
194 * Resize the given framebuffer's renderbuffers to the new width and height.
195 * This should only be used for window-system framebuffers, not
196 * user-created renderbuffers (i.e. made with GL_EXT_framebuffer_object).
197 * This will typically be called via ctx->Driver.ResizeBuffers()
198 */
199 void
200 _mesa_resize_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb,
201 GLuint width, GLuint height)
202 {
203 GLuint i;
204
205 /* For window system framebuffers, Name is zero */
206 assert(fb->Name == 0);
207
208 for (i = 0; i < BUFFER_COUNT; i++) {
209 struct gl_renderbuffer_attachment *att = &fb->Attachment[i];
210 if (att->Type == GL_RENDERBUFFER_EXT && att->Renderbuffer) {
211 struct gl_renderbuffer *rb = att->Renderbuffer;
212 /* only resize if size is changing */
213 if (rb->Width != width || rb->Height != height) {
214 if (rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) {
215 rb->Width = width;
216 rb->Height = height;
217 }
218 else {
219 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer");
220 }
221 }
222 }
223 }
224
225 fb->Width = width;
226 fb->Height = height;
227
228 /* to update scissor / window bounds */
229 ctx->NewState |= _NEW_BUFFERS;
230 }
231
232
233 /**
234 * Examine all the framebuffer's renderbuffers to update the Width/Height
235 * fields of the framebuffer. If we have renderbuffers with different
236 * sizes, set the framebuffer's width and height to zero.
237 * Note: this is only intended for user-created framebuffers, not
238 * window-system framebuffes.
239 */
240 static void
241 update_framebuffer_size(struct gl_framebuffer *fb)
242 {
243 GLboolean haveSize = GL_FALSE;
244 GLuint i;
245
246 /* user-created framebuffers only */
247 assert(fb->Name);
248
249 for (i = 0; i < BUFFER_COUNT; i++) {
250 struct gl_renderbuffer_attachment *att = &fb->Attachment[i];
251 const struct gl_renderbuffer *rb = att->Renderbuffer;
252 if (rb) {
253 if (haveSize) {
254 if (rb->Width != fb->Width && rb->Height != fb->Height) {
255 /* size mismatch! */
256 fb->Width = 0;
257 fb->Height = 0;
258 return;
259 }
260 }
261 else {
262 fb->Width = rb->Width;
263 fb->Height = rb->Height;
264 haveSize = GL_TRUE;
265 }
266 }
267 }
268 }
269
270
271 /**
272 * Update the context's current drawing buffer's Xmin, Xmax, Ymin, Ymax fields.
273 * These values are computed from the buffer's width and height and
274 * the scissor box, if it's enabled.
275 * \param ctx the GL context.
276 */
277 void
278 _mesa_update_draw_buffer_bounds(GLcontext *ctx)
279 {
280 struct gl_framebuffer *buffer = ctx->DrawBuffer;
281
282 if (buffer->Name) {
283 /* user-created framebuffer size depends on the renderbuffers */
284 update_framebuffer_size(buffer);
285 }
286
287 buffer->_Xmin = 0;
288 buffer->_Ymin = 0;
289 buffer->_Xmax = buffer->Width;
290 buffer->_Ymax = buffer->Height;
291
292 if (ctx->Scissor.Enabled) {
293 if (ctx->Scissor.X > buffer->_Xmin) {
294 buffer->_Xmin = ctx->Scissor.X;
295 }
296 if (ctx->Scissor.Y > buffer->_Ymin) {
297 buffer->_Ymin = ctx->Scissor.Y;
298 }
299 if (ctx->Scissor.X + ctx->Scissor.Width < buffer->_Xmax) {
300 buffer->_Xmax = ctx->Scissor.X + ctx->Scissor.Width;
301 }
302 if (ctx->Scissor.Y + ctx->Scissor.Height < buffer->_Ymax) {
303 buffer->_Ymax = ctx->Scissor.Y + ctx->Scissor.Height;
304 }
305 /* finally, check for empty region */
306 if (buffer->_Xmin > buffer->_Xmax) {
307 buffer->_Xmin = buffer->_Xmax;
308 }
309 if (buffer->_Ymin > buffer->_Ymax) {
310 buffer->_Ymin = buffer->_Ymax;
311 }
312 }
313
314 ASSERT(buffer->_Xmin <= buffer->_Xmax);
315 ASSERT(buffer->_Ymin <= buffer->_Ymax);
316 }
317
318
319 /**
320 * The glGet queries of the framebuffer red/green/blue size, stencil size,
321 * etc. are satisfied by the fields of ctx->DrawBuffer->Visual. These can
322 * change depending on the renderbuffer bindings. This function updates
323 * the given framebuffer's Visual from the current renderbuffer bindings.
324 * This is only intended for user-created framebuffers.
325 *
326 * Also note: ctx->DrawBuffer->Visual.depthBits might not equal
327 * ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer.DepthBits.
328 * The former one is used to convert floating point depth values into
329 * integer Z values.
330 */
331 void
332 _mesa_update_framebuffer_visual(struct gl_framebuffer *fb)
333 {
334 GLuint i;
335
336 assert(fb->Name != 0);
337
338 _mesa_bzero(&fb->Visual, sizeof(fb->Visual));
339 fb->Visual.rgbMode = GL_TRUE; /* assume this */
340
341 /* find first RGB or CI renderbuffer */
342 for (i = 0; i < BUFFER_COUNT; i++) {
343 if (fb->Attachment[i].Renderbuffer) {
344 const struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer;
345 if (rb->_BaseFormat == GL_RGBA || rb->_BaseFormat == GL_RGB) {
346 fb->Visual.redBits = rb->RedBits;
347 fb->Visual.greenBits = rb->GreenBits;
348 fb->Visual.blueBits = rb->BlueBits;
349 fb->Visual.alphaBits = rb->AlphaBits;
350 fb->Visual.rgbBits = fb->Visual.redBits
351 + fb->Visual.greenBits + fb->Visual.blueBits;
352 fb->Visual.floatMode = GL_FALSE;
353 break;
354 }
355 else if (rb->_BaseFormat == GL_COLOR_INDEX) {
356 fb->Visual.indexBits = rb->IndexBits;
357 fb->Visual.rgbMode = GL_FALSE;
358 break;
359 }
360 }
361 }
362
363 if (fb->Attachment[BUFFER_DEPTH].Renderbuffer) {
364 fb->Visual.haveDepthBuffer = GL_TRUE;
365 fb->Visual.depthBits
366 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->DepthBits;
367 }
368
369 if (fb->Attachment[BUFFER_STENCIL].Renderbuffer) {
370 fb->Visual.haveStencilBuffer = GL_TRUE;
371 fb->Visual.stencilBits
372 = fb->Attachment[BUFFER_STENCIL].Renderbuffer->StencilBits;
373 }
374
375 compute_depth_max(fb);
376 }
377
378
379 /**
380 * Update state related to the current draw/read framebuffers.
381 * Specifically, update these framebuffer fields:
382 * _ColorDrawBuffers
383 * _NumColorDrawBuffers
384 * _ColorReadBuffer
385 * If the current framebuffer is user-created, make sure it's complete.
386 * The following functions can effect this state: glReadBuffer,
387 * glDrawBuffer, glDrawBuffersARB, glFramebufferRenderbufferEXT.
388 */
389 void
390 _mesa_update_framebuffer(GLcontext *ctx)
391 {
392 struct gl_framebuffer *fb = ctx->DrawBuffer;
393 GLuint output;
394
395 /* Completeness only matters for user-created framebuffers */
396 if (fb->Name != 0) {
397 _mesa_test_framebuffer_completeness(ctx, fb);
398 _mesa_update_framebuffer_visual(fb);
399 }
400
401 /*
402 * Update the list of color drawing renderbuffer pointers.
403 * Later, when we're rendering we'll loop from 0 to _NumColorDrawBuffers
404 * writing colors. We need the inner loop here because
405 * glDrawBuffer(GL_FRONT_AND_BACK) can specify writing to two or four
406 * color buffers (for example).
407 */
408 for (output = 0; output < ctx->Const.MaxDrawBuffers; output++) {
409 GLbitfield bufferMask = fb->_ColorDrawBufferMask[output];
410 GLuint count = 0;
411 GLuint i;
412 for (i = 0; bufferMask && i < BUFFER_COUNT; i++) {
413 const GLuint bufferBit = 1 << i;
414 if (bufferBit & bufferMask) {
415 struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer;
416 if (rb) {
417 fb->_ColorDrawBuffers[output][count] = rb;
418 count++;
419 }
420 else {
421 /*_mesa_warning(ctx, "DrawBuffer names a missing buffer!\n");*/
422 }
423 bufferMask &= ~bufferBit;
424 }
425 }
426 fb->_NumColorDrawBuffers[output] = count;
427 }
428
429 /*
430 * Update the color read renderbuffer pointer.
431 * Unlike the DrawBuffer, we can only read from one (or zero) color buffers.
432 */
433 if (fb->_ColorReadBufferIndex == -1) {
434 fb->_ColorReadBuffer = NULL; /* legal! */
435 }
436 else {
437 ASSERT(fb->_ColorReadBufferIndex >= 0);
438 ASSERT(fb->_ColorReadBufferIndex < BUFFER_COUNT);
439 fb->_ColorReadBuffer
440 = fb->Attachment[fb->_ColorReadBufferIndex].Renderbuffer;
441 }
442 compute_depth_max(fb);
443 }