framebuffer.c revision 79b4dbc4961a80e6a88235ae7455ffdcec23e982
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 */
47static void
48compute_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 */
78struct 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 */
97struct 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 */
121void
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
148   compute_depth_max(fb);
149}
150
151
152/**
153 * Deallocate buffer and everything attached to it.
154 * Typically called via the gl_framebuffer->Delete() method.
155 */
156void
157_mesa_destroy_framebuffer(struct gl_framebuffer *fb)
158{
159   if (fb) {
160      _mesa_free_framebuffer_data(fb);
161      FREE(fb);
162   }
163}
164
165
166/**
167 * Free all the data hanging off the given gl_framebuffer, but don't free
168 * the gl_framebuffer object itself.
169 */
170void
171_mesa_free_framebuffer_data(struct gl_framebuffer *fb)
172{
173   GLuint i;
174
175   assert(fb);
176
177   for (i = 0; i < BUFFER_COUNT; i++) {
178      struct gl_renderbuffer_attachment *att = &fb->Attachment[i];
179      if (att->Type == GL_RENDERBUFFER_EXT && att->Renderbuffer) {
180         struct gl_renderbuffer *rb = att->Renderbuffer;
181         rb->RefCount--;
182         if (rb->RefCount == 0) {
183            rb->Delete(rb);
184         }
185      }
186      att->Type = GL_NONE;
187      att->Renderbuffer = NULL;
188   }
189}
190
191
192/**
193 * Resize the given framebuffer's renderbuffers to the new width and height.
194 * This should only be used for window-system framebuffers, not
195 * user-created renderbuffers (i.e. made with GL_EXT_framebuffer_object).
196 * This will typically be called via ctx->Driver.ResizeBuffers()
197 */
198void
199_mesa_resize_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb,
200                         GLuint width, GLuint height)
201{
202   GLuint i;
203
204   /* For window system framebuffers, Name is zero */
205   assert(fb->Name == 0);
206
207   for (i = 0; i < BUFFER_COUNT; i++) {
208      struct gl_renderbuffer_attachment *att = &fb->Attachment[i];
209      if (att->Type == GL_RENDERBUFFER_EXT && att->Renderbuffer) {
210         struct gl_renderbuffer *rb = att->Renderbuffer;
211         /* only resize if size is changing */
212         if (rb->Width != width || rb->Height != height) {
213            if (rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) {
214               rb->Width = width;
215               rb->Height = height;
216            }
217            else {
218               _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer");
219            }
220         }
221      }
222   }
223
224   fb->Width = width;
225   fb->Height = height;
226}
227
228
229/**
230 * Examine all the framebuffer's renderbuffers to update the Width/Height
231 * fields of the framebuffer.  If we have renderbuffers with different
232 * sizes, set the framebuffer's width and height to zero.
233 * Note: this is only intended for user-created framebuffers, not
234 * window-system framebuffes.
235 */
236static void
237update_framebuffer_size(struct gl_framebuffer *fb)
238{
239   GLboolean haveSize = GL_FALSE;
240   GLuint i;
241
242   /* user-created framebuffers only */
243   assert(fb->Name);
244
245   for (i = 0; i < BUFFER_COUNT; i++) {
246      struct gl_renderbuffer_attachment *att = &fb->Attachment[i];
247      const struct gl_renderbuffer *rb = att->Renderbuffer;
248      if (rb) {
249         if (haveSize) {
250            if (rb->Width != fb->Width && rb->Height != fb->Height) {
251               /* size mismatch! */
252               fb->Width = 0;
253               fb->Height = 0;
254               return;
255            }
256         }
257         else {
258            fb->Width = rb->Width;
259            fb->Height = rb->Height;
260            haveSize = GL_TRUE;
261         }
262      }
263   }
264}
265
266
267/**
268 * Update the context's current drawing buffer's Xmin, Xmax, Ymin, Ymax fields.
269 * These values are computed from the buffer's width and height and
270 * the scissor box, if it's enabled.
271 * \param ctx  the GL context.
272 */
273void
274_mesa_update_draw_buffer_bounds(GLcontext *ctx)
275{
276   struct gl_framebuffer *buffer = ctx->DrawBuffer;
277
278   if (buffer->Name) {
279      /* user-created framebuffer size depends on the renderbuffers */
280      update_framebuffer_size(buffer);
281   }
282
283   buffer->_Xmin = 0;
284   buffer->_Ymin = 0;
285   buffer->_Xmax = buffer->Width;
286   buffer->_Ymax = buffer->Height;
287
288   if (ctx->Scissor.Enabled) {
289      if (ctx->Scissor.X > buffer->_Xmin) {
290	 buffer->_Xmin = ctx->Scissor.X;
291      }
292      if (ctx->Scissor.Y > buffer->_Ymin) {
293	 buffer->_Ymin = ctx->Scissor.Y;
294      }
295      if (ctx->Scissor.X + ctx->Scissor.Width < buffer->_Xmax) {
296	 buffer->_Xmax = ctx->Scissor.X + ctx->Scissor.Width;
297      }
298      if (ctx->Scissor.Y + ctx->Scissor.Height < buffer->_Ymax) {
299	 buffer->_Ymax = ctx->Scissor.Y + ctx->Scissor.Height;
300      }
301      /* finally, check for empty region */
302      if (buffer->_Xmin > buffer->_Xmax) {
303         buffer->_Xmin = buffer->_Xmax;
304      }
305      if (buffer->_Ymin > buffer->_Ymax) {
306         buffer->_Ymin = buffer->_Ymax;
307      }
308   }
309
310   ASSERT(buffer->_Xmin <= buffer->_Xmax);
311   ASSERT(buffer->_Ymin <= buffer->_Ymax);
312}
313
314
315/**
316 * The glGet queries of the framebuffer red/green/blue size, stencil size,
317 * etc. are satisfied by the fields of ctx->DrawBuffer->Visual.  These can
318 * change depending on the renderbuffer bindings.  This function updates
319 * the given framebuffer's Visual from the current renderbuffer bindings.
320 * This is only intended for user-created framebuffers.
321 */
322void
323_mesa_update_framebuffer_visual(struct gl_framebuffer *fb)
324{
325   assert(fb->Name != 0);
326
327   _mesa_bzero(&fb->Visual, sizeof(fb->Visual));
328   fb->Visual.rgbMode = GL_TRUE;
329
330   if (fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer) {
331      fb->Visual.redBits
332         = fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer->RedBits;
333      fb->Visual.greenBits
334         = fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer->GreenBits;
335      fb->Visual.blueBits
336         = fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer->BlueBits;
337      fb->Visual.alphaBits
338         = fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer->AlphaBits;
339      fb->Visual.rgbBits
340         = fb->Visual.redBits + fb->Visual.greenBits + fb->Visual.blueBits;
341      fb->Visual.floatMode = GL_FALSE;
342   }
343
344   if (fb->Attachment[BUFFER_DEPTH].Renderbuffer) {
345      fb->Visual.haveDepthBuffer = GL_TRUE;
346      fb->Visual.depthBits
347         = fb->Attachment[BUFFER_DEPTH].Renderbuffer->DepthBits;
348   }
349
350   if (fb->Attachment[BUFFER_STENCIL].Renderbuffer) {
351      fb->Visual.haveStencilBuffer = GL_TRUE;
352      fb->Visual.stencilBits
353         = fb->Attachment[BUFFER_STENCIL].Renderbuffer->StencilBits;
354   }
355
356   compute_depth_max(fb);
357}
358
359
360/**
361 * Update state related to the current draw/read framebuffers.
362 * Specifically, update these framebuffer fields:
363 *    _ColorDrawBuffers
364 *    _NumColorDrawBuffers
365 *    _ColorReadBuffer
366 * If the current framebuffer is user-created, make sure it's complete.
367 * The following functions can effect this state:  glReadBuffer,
368 * glDrawBuffer, glDrawBuffersARB, glFramebufferRenderbufferEXT.
369 */
370void
371_mesa_update_framebuffer(GLcontext *ctx)
372{
373   struct gl_framebuffer *fb = ctx->DrawBuffer;
374   GLuint output;
375
376   /* Completeness only matters for user-created framebuffers */
377   if (fb->Name != 0)
378      _mesa_test_framebuffer_completeness(ctx, fb);
379
380   /*
381    * Update the list of color drawing renderbuffer pointers.
382    * Later, when we're rendering we'll loop from 0 to _NumColorDrawBuffers
383    * writing colors.  We need the inner loop here because
384    * glDrawBuffer(GL_FRONT_AND_BACK) can specify writing to two or four
385    * color buffers (for example).
386    */
387   for (output = 0; output < ctx->Const.MaxDrawBuffers; output++) {
388      GLbitfield bufferMask = fb->_ColorDrawBufferMask[output];
389      GLuint count = 0;
390      GLuint i;
391      for (i = 0; bufferMask && i < BUFFER_COUNT; i++) {
392         const GLuint bufferBit = 1 << i;
393         if (bufferBit & bufferMask) {
394            struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer;
395            if (rb) {
396               fb->_ColorDrawBuffers[output][count] = rb;
397               count++;
398            }
399            else {
400               _mesa_warning(ctx, "DrawBuffer names a missing buffer!");
401            }
402            bufferMask &= ~bufferBit;
403         }
404      }
405      fb->_NumColorDrawBuffers[output] = count;
406   }
407
408   /*
409    * Update the color read renderbuffer pointer.
410    * Unlike the DrawBuffer, we can only read from one (or zero) color buffers.
411    */
412   if (fb->_ColorReadBufferIndex == -1) {
413      fb->_ColorReadBuffer = NULL; /* legal! */
414   }
415   else {
416      ASSERT(fb->_ColorReadBufferIndex >= 0);
417      ASSERT(fb->_ColorReadBufferIndex < BUFFER_COUNT);
418      fb->_ColorReadBuffer
419         = fb->Attachment[fb->_ColorReadBufferIndex].Renderbuffer;
420   }
421   compute_depth_max(fb);
422}
423